diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..c4b17d7 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use_flake diff --git a/.gitignore b/.gitignore index efd04b7..9c8f2fa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,181 @@ /build/* /out/build/x64-Debug /.vs + +# cmake +cmake-build-debug + +# direnv +.direnv + +#binarys +bin_x64 + +# Created by https://www.toptal.com/developers/gitignore/api/clion,cmake,c++ +# Edit at https://www.toptal.com/developers/gitignore?templates=clion,cmake,c++ + +### C++ ### +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +### CLion ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### CLion Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### CMake ### +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +### CMake Patch ### +# External projects +*-prefix/ + +# End of https://www.toptal.com/developers/gitignore/api/clion,cmake,c++ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b38da54 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "nvpro_core"] + path = nvpro_core + url = git@github.com:nvpro-samples/nvpro_core.git diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..a4d4a59 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +vk_raytracing_tutorial \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..eaf5af8 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0b76fe5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8a648f1 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..6732266 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/vk_raytracing_tutorial_KHR.iml b/.idea/vk_raytracing_tutorial_KHR.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/vk_raytracing_tutorial_KHR.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ff7ace..59ccf28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,25 +41,7 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/media DESTINATION ${OUTPUT_PATH}) #-------------------------------------------------------------------------------------------------- # Sub examples -add_subdirectory(ray_tracing__advance) -add_subdirectory(ray_tracing__before) -add_subdirectory(ray_tracing__simple) - -add_subdirectory(ray_tracing_animation) -add_subdirectory(ray_tracing_anyhit) -add_subdirectory(ray_tracing_callable) add_subdirectory(ray_tracing_gltf) -add_subdirectory(ray_tracing_instances) -add_subdirectory(ray_tracing_intersection) -add_subdirectory(ray_tracing_jitter_cam) -add_subdirectory(ray_tracing_manyhits) -add_subdirectory(ray_tracing_rayquery) -add_subdirectory(ray_tracing_reflections) -add_subdirectory(ray_tracing_ao) -add_subdirectory(ray_tracing_indirect_scissor) -add_subdirectory(ray_tracing_specialization) -add_subdirectory(ray_tracing_advanced_compilation) -add_subdirectory(ray_tracing_motionblur) #-------------------------------------------------------------------------------------------------- diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..df4c399 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1715266358, + "narHash": "sha256-doPgfj+7FFe9rfzWo1siAV2mVCasW+Bh8I1cToAXEE4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "f1010e0469db743d14519a1efd37e23f8513d714", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..7dd176e --- /dev/null +++ b/flake.nix @@ -0,0 +1,66 @@ +{ + description = "Nix flake for developing with vulkan and cpp"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + }; + + outputs = { self, nixpkgs }: + let + allSystems = [ + "x86_64-linux" # 64bit AMD/Intel x86 + ]; + + forAllSystems = fn: + nixpkgs.lib.genAttrs allSystems + (system: fn { pkgs = import nixpkgs { inherit system; }; }); + + in + { + devShells = forAllSystems ({ pkgs }: { + default = pkgs.mkShell { + name = "vulkan CPP dev shell"; + # gcc appears to be broken + nativeBuildInputs = with pkgs ;[ + (hiPrio clang-tools.override { + llvmPackages = llvmPackages_16; + enableLibcxx = false; + }) + # CPP deps + clang-tools + glm + cmake + # Vulkan Deps + vulkan-tools + vulkan-headers + vulkan-loader + vulkan-validation-layers + shaderc + shaderc.dev + shaderc.lib + shaderc.bin + shaderc.static + glslang + # X11 Deps + xorg.libX11 + xorg.libXi + xorg.libXxf86vm + xorg.libXrandr + xorg.libXinerama + xorg.libXcursor + glfw + # Wayland deps + glfw-wayland + waylandpp + wayland + # dev tools + valgrind + # general deps + imgui + ]; + # TODO: include deps depending on XDG_SESSION_TYPE here (wayland vs X11) + }; + }); + }; +} + diff --git a/nvpro_core b/nvpro_core new file mode 160000 index 0000000..c98df79 --- /dev/null +++ b/nvpro_core @@ -0,0 +1 @@ +Subproject commit c98df794436fed19c17d3eb12f6ff8e5002ce2c4 diff --git a/ray_tracing__advance/CMakeLists.txt b/ray_tracing__advance/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing__advance/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing__advance/README.md b/ray_tracing__advance/README.md deleted file mode 100644 index d2cd1f1..0000000 --- a/ray_tracing__advance/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# NVIDIA Vulkan Ray Tracing Tutorial - -This example is the combination of all tutorials. - -If you haven't done the tutorials, you can start [here](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html) - -![](../docs/Images/ray_tracing__advance.png) diff --git a/ray_tracing__advance/hello_vulkan.cpp b/ray_tracing__advance/hello_vulkan.cpp deleted file mode 100644 index 99f88e2..0000000 --- a/ray_tracing__advance/hello_vulkan.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define VMA_IMPLEMENTATION - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - - -#include "hello_vulkan.h" -#include "nvh/cameramanipulator.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" - -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" - -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - - - m_offscreen.setup(device, physicalDevice, &m_alloc, queueFamily); - m_raytrace.setup(device, physicalDevice, &m_alloc, queueFamily); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT - | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); - - // Storing implicit obj (binding = 3) - m_descSetLayoutBind.addBinding(eImplicits, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR - | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - VkDescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 3, &dbiImplDesc)); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass()); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - m_alloc.destroy(m_implObjects.implBuf); - m_alloc.destroy(m_implObjects.implMatBuf); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_offscreen.destroy(); - - // #VKRay - m_raytrace.destroy(); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - auto nbInst = static_cast(m_instances.size() - 1); // Remove the implicit object - for(uint32_t i = 0; i < nbInst; ++i) - { - auto& inst = m_instances[i]; - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - m_offscreen.createFramebuffer(m_size); - m_offscreen.updateDescriptorSet(); - m_raytrace.updateRtDescriptorSet(m_offscreen.colorTexture().descriptor.imageView); - resetFrame(); -} - -//-------------------------------------------------------------------------------------------------- -// Initialize offscreen rendering -// -void HelloVulkan::initOffscreen() -{ - m_offscreen.createFramebuffer(m_size); - m_offscreen.createDescriptor(); - m_offscreen.createPipeline(m_renderPass); - m_offscreen.updateDescriptorSet(); -} - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// -void HelloVulkan::initRayTracing() -{ - m_raytrace.createBottomLevelAS(m_objModel, m_implObjects); - m_raytrace.createTopLevelAS(m_instances, m_implObjects); - m_raytrace.createRtDescriptorSet(m_offscreen.colorTexture().descriptor.imageView); - m_raytrace.createRtPipeline(m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Ray trace the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - updateFrame(); - if(m_pcRaster.frame >= m_maxFrames) - return; - - m_raytrace.raytrace(cmdBuf, clearColor, m_descSet, m_size, m_pcRaster); -} - -//-------------------------------------------------------------------------------------------------- -// If the camera matrix has changed, resets the frame. -// otherwise, increments frame. -// -void HelloVulkan::updateFrame() -{ - static glm::mat4 refCamMatrix; - static float refFov{CameraManip.getFov()}; - - const auto& m = CameraManip.getMatrix(); - const auto fov = CameraManip.getFov(); - - if(refCamMatrix != m || refFov != fov) - { - resetFrame(); - refCamMatrix = m; - refFov = fov; - } - m_pcRaster.frame++; -} - -void HelloVulkan::resetFrame() -{ - m_pcRaster.frame = -1; -} - - -void HelloVulkan::addImplSphere(glm::vec3 center, float radius, int matId) -{ - ObjImplicit impl; - impl.minimum = center - radius; - impl.maximum = center + radius; - impl.objType = EObjType::eSphere; - impl.matId = matId; - m_implObjects.objImpl.push_back(impl); -} - -void HelloVulkan::addImplCube(glm::vec3 minumum, glm::vec3 maximum, int matId) -{ - ObjImplicit impl; - impl.minimum = minumum; - impl.maximum = maximum; - impl.objType = EObjType::eCube; - impl.matId = matId; - m_implObjects.objImpl.push_back(impl); -} - -void HelloVulkan::addImplMaterial(const MaterialObj& mat) -{ - m_implObjects.implMat.push_back(mat); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createImplictBuffers() -{ - using vkBU = VkBufferUsageFlagBits; - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - // Not allowing empty buffers - if(m_implObjects.objImpl.empty()) - m_implObjects.objImpl.push_back({}); - if(m_implObjects.implMat.empty()) - m_implObjects.implMat.push_back({}); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl, - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR - | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); - m_implObjects.implMatBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.implMat, - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj"); - m_debug.setObjectName(m_implObjects.implMatBuf.buffer, "implicitMat"); - - - // Adding an extra instance to get access to the material buffers - ObjDesc objDesc{}; - objDesc.materialAddress = nvvk::getBufferDeviceAddress(m_device, m_implObjects.implMatBuf.buffer); - m_objDesc.emplace_back(objDesc); - - ObjInstance instance{}; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.emplace_back(instance); -} diff --git a/ray_tracing__advance/hello_vulkan.h b/ray_tracing__advance/hello_vulkan.h deleted file mode 100644 index fe8f216..0000000 --- a/ray_tracing__advance/hello_vulkan.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" -#include "offscreen.hpp" - -#include "obj.hpp" -#include "raytrace.hpp" - -#include - -// Choosing the allocator to use -#define ALLOC_DMA -//#define ALLOC_DEDICATED -//#define ALLOC_VMA -#include - -#if defined(ALLOC_DMA) -#include -using Allocator = nvvk::ResourceAllocatorDma; -#elif defined(ALLOC_VMA) -#include -using Allocator = nvvk::ResourceAllocatorVma; -#else -using Allocator = nvvk::ResourceAllocatorDedicated; -#endif - - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - Offscreen& offscreen() { return m_offscreen; } - Raytracer& raytracer() { return m_raytrace; } - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - {-1.f, -1.f, -.4f}, // lightDirection; - 0.939692621f, // {cos(glm::radians(20.0f))}, // lightSpotCutoff; - 0.866025404f, // {cos(glm::radians(30.0f))}, // lightSpotOuterCutoff; - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - int m_maxFrames{500}; - void resetFrame(); - void updateFrame(); - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - Allocator m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - // #Post - Offscreen m_offscreen; - void initOffscreen(); - - - // #VKRay - Raytracer m_raytrace; - - void initRayTracing(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - // Implicit - ImplInst m_implObjects; - - void addImplSphere(glm::vec3 center, float radius, int matId); - void addImplCube(glm::vec3 minumum, glm::vec3 maximum, int matId); - void addImplMaterial(const MaterialObj& mat); - void createImplictBuffers(); -}; diff --git a/ray_tracing__advance/images/ray_tracing__advance.png b/ray_tracing__advance/images/ray_tracing__advance.png deleted file mode 100644 index 49b3236..0000000 Binary files a/ray_tracing__advance/images/ray_tracing__advance.png and /dev/null differ diff --git a/ray_tracing__advance/main.cpp b/ray_tracing__advance/main.cpp deleted file mode 100644 index f940bb5..0000000 --- a/ray_tracing__advance/main.cpp +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - -#include - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - bool changed = false; - - changed |= ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - auto& pc = helloVk.m_pcRaster; - - changed |= ImGui::RadioButton("Point", &pc.lightType, 0); - ImGui::SameLine(); - changed |= ImGui::RadioButton("Spot", &pc.lightType, 1); - ImGui::SameLine(); - changed |= ImGui::RadioButton("Infinite", &pc.lightType, 2); - - - if(pc.lightType < 2) - { - changed |= ImGui::SliderFloat3("Light Position", &pc.lightPosition.x, -20.f, 20.f); - } - if(pc.lightType > 0) - { - changed |= ImGui::SliderFloat3("Light Direction", &pc.lightDirection.x, -1.f, 1.f); - } - if(pc.lightType < 2) - { - changed |= ImGui::SliderFloat("Light Intensity", &pc.lightIntensity, 0.f, 500.f); - } - if(pc.lightType == 1) - { - float dCutoff = glm::degrees(acos(pc.lightSpotCutoff)); - float dOutCutoff = glm::degrees(acos(pc.lightSpotOuterCutoff)); - changed |= ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f); - changed |= ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f); - dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff; - - pc.lightSpotCutoff = cos(glm::radians(dCutoff)); - pc.lightSpotOuterCutoff = cos(glm::radians(dOutCutoff)); - } - } - - changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 1000); - if(changed) - helloVk.resetFrame(); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat({8.440, 9.041, -8.973}, {-2.462, 3.661, -0.286}, {0.000, 1.000, 0.000}); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), - glm::scale(glm::mat4(1.f), glm::vec3(0.5f)) * glm::translate(glm::mat4(1.f), glm::vec3(0.0f, 0.0f, 6.0f))); - - 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::normal_distribution dis(2.0f, 2.0f); - std::normal_distribution disn(0.5f, 0.2f); - auto wusonIndex = static_cast(helloVk.m_objModel.size() - 1); - - for(int n = 0; n < 50; ++n) - { - ObjInstance inst; - inst.objIndex = wusonIndex; - float scale = fabsf(disn(gen)); - glm::mat4 mat = glm::translate(glm::mat4(1), glm::vec3{dis(gen), 0.f, dis(gen) + 6}); - // mat = mat * glm::rotation_mat4_x(dis(gen)); - mat = glm::scale(mat, glm::vec3(scale)); - inst.transform = mat; - - helloVk.m_instances.push_back(inst); - } - - // Creation of implicit geometry - MaterialObj mat; - // Reflective - mat.diffuse = glm::vec3(0, 0, 0); - mat.specular = glm::vec3(1.f); - mat.shininess = 0.0; - mat.illum = 3; - helloVk.addImplMaterial(mat); - // Transparent - mat.diffuse = glm::vec3(0.4, 0.4, 1); - mat.illum = 4; - mat.dissolve = 0.5; - helloVk.addImplMaterial(mat); - helloVk.addImplCube({-6.1, 0, -6}, {-6, 10, 6}, 0); - helloVk.addImplSphere({1, 2, 4}, 1.f, 1); - - - helloVk.initOffscreen(); - Offscreen& offscreen = helloVk.offscreen(); - - helloVk.createImplictBuffers(); - - - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - bool changed = false; - // Edit 3 floats representing a color - changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - // Switch between raster and ray tracing - changed |= ImGui::Checkbox("Ray Tracer mode", &useRaytracer); - if(changed) - helloVk.resetFrame(); - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = offscreen.renderPass(); - offscreenRenderPassBeginInfo.framebuffer = offscreen.frameBuffer(); - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - offscreen.draw(cmdBuf, helloVk.getSize()); - - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing__advance/obj.hpp b/ray_tracing__advance/obj.hpp deleted file mode 100644 index 9f17269..0000000 --- a/ray_tracing__advance/obj.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once -#include "obj_loader.h" - - -// The OBJ model -struct ObjModel -{ - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' -}; - -struct ObjInstance -{ - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference -}; - - -enum EObjType -{ - eSphere = 0, - eCube -}; - -// One single implicit object -struct ObjImplicit -{ - glm::vec3 minimum{0, 0, 0}; // Aabb - glm::vec3 maximum{0, 0, 0}; // Aabb - int objType{0}; // 0: Sphere, 1: Cube - int matId{0}; -}; - -// All implicit objects -struct ImplInst -{ - std::vector objImpl; // All objects - std::vector implMat; // All materials used by implicit obj - nvvk::Buffer implBuf; // Buffer of objects - nvvk::Buffer implMatBuf; // Buffer of material - int blasId{0}; - glm::mat4 transform{1}; -}; diff --git a/ray_tracing__advance/offscreen.cpp b/ray_tracing__advance/offscreen.cpp deleted file mode 100644 index 8d6a73a..0000000 --- a/ray_tracing__advance/offscreen.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include "offscreen.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" - -extern std::vector defaultSearchPaths; - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - -void Offscreen::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily) -{ - m_device = device; - m_alloc = allocator; - m_graphicsQueueIndex = queueFamily; - m_debug.setup(m_device); - m_depthFormat = nvvk::findDepthFormat(physicalDevice); -} - -void Offscreen::destroy() -{ - vkDestroyPipeline(m_device, m_pipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_dsetLayout, nullptr); - vkDestroyRenderPass(m_device, m_renderPass, nullptr); - vkDestroyFramebuffer(m_device, m_framebuffer, nullptr); - m_alloc->destroy(m_colorTexture); - m_alloc->destroy(m_depthTexture); -} - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void Offscreen::createFramebuffer(const VkExtent2D& size) -{ - m_alloc->destroy(m_colorTexture); - m_alloc->destroy(m_depthTexture); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo( - size, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT); - - nvvk::Image image = m_alloc->createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_colorTexture = m_alloc->createTexture(image, ivInfo, sampler); - m_colorTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - - // Creating the depth buffer - { - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(size, m_depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - nvvk::Image image = m_alloc->createImage(depthCreateInfo); - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_depthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_depthTexture = m_alloc->createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_renderPass) - { - m_renderPass = nvvk::createRenderPass(m_device, {m_colorFormat}, m_depthFormat, 1, true, true, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - // Creating the frame buffer for offscreen - std::vector attachments = {m_colorTexture.descriptor.imageView, m_depthTexture.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_framebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_renderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = size.width; - info.height = size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_framebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// The incoming render pass, is in which rendering pass it will be displayed (framebuffer) -// -void Offscreen::createPipeline(VkRenderPass& renderPass) -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.setLayoutCount = 1; - pipelineLayoutCreateInfo.pSetLayouts = &m_dsetLayout; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_pipelineLayout); - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_pipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_pipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void Offscreen::createDescriptor() -{ - m_dsetLayoutBinding.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_dsetLayout = m_dsetLayoutBinding.createLayout(m_device); - m_descPool = m_dsetLayoutBinding.createPool(m_device); - m_dset = nvvk::allocateDescriptorSet(m_device, m_descPool, m_dsetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void Offscreen::updateDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void Offscreen::draw(VkCommandBuffer cmdBuf, const VkExtent2D& size) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - VkViewport viewport{0, 0, (float)size.width, (float)size.height, 0, 1}; - vkCmdSetViewport(cmdBuf, 0, 1, &viewport); - VkRect2D scissor{{0, 0}, {size.width, size.height}}; - vkCmdSetScissor(cmdBuf, 0, 1, &scissor); - - - auto aspectRatio = static_cast(size.width) / static_cast(size.height); - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_dset, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing__advance/offscreen.hpp b/ray_tracing__advance/offscreen.hpp deleted file mode 100644 index 5d744d1..0000000 --- a/ray_tracing__advance/offscreen.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Class to render in off-screen framebuffers. Instead of rendering directly to the -// screen back buffer, this class create the output frame buffer 'createFramebuffer', -// and use the pipeline from 'createPipeline' to render a quad 'draw' with the colorTexture -// image - -class Offscreen -{ -public: - void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily); - void destroy(); - - void createFramebuffer(const VkExtent2D& size); - void createPipeline(VkRenderPass& renderPass); - void createDescriptor(); - void updateDescriptorSet(); - void draw(VkCommandBuffer cmdBuf, const VkExtent2D& size); - - const VkRenderPass& renderPass() { return m_renderPass; } - const VkFramebuffer& frameBuffer() { return m_framebuffer; } - const nvvk::Texture& colorTexture() { return m_colorTexture; } - -private: - nvvk::DescriptorSetBindings m_dsetLayoutBinding; - VkDescriptorPool m_descPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_dsetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_dset{VK_NULL_HANDLE}; - VkPipeline m_pipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_renderPass{VK_NULL_HANDLE}; - VkFramebuffer m_framebuffer{VK_NULL_HANDLE}; - - nvvk::Texture m_colorTexture; - VkFormat m_colorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - nvvk::Texture m_depthTexture; - VkFormat m_depthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures - VkDevice m_device; - int m_graphicsQueueIndex{0}; - nvvk::DebugUtil m_debug; // Utility to name objects -}; diff --git a/ray_tracing__advance/raytrace.cpp b/ray_tracing__advance/raytrace.cpp deleted file mode 100644 index 6e181c5..0000000 --- a/ray_tracing__advance/raytrace.cpp +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include "raytrace.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/descriptorsets_vk.hpp" - -#include "nvh/alignment.hpp" -#include "nvvk/shaders_vk.hpp" -#include "obj_loader.h" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -void Raytracer::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily) -{ - m_device = device; - m_physicalDevice = physicalDevice; - m_alloc = allocator; - m_graphicsQueueIndex = queueFamily; - - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex); - m_sbtWrapper.setup(device, queueFamily, allocator, m_rtProperties); - m_debug.setup(device); -} - - -void Raytracer::destroy() -{ - m_sbtWrapper.destroy(); - m_rtBuilder.destroy(); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - m_alloc->destroy(m_rtSBTBuffer); -} - -//-------------------------------------------------------------------------------------------------- -// Converting a OBJ primitive to the ray tracing geometry used for the BLAS -// -auto Raytracer::objectToVkGeometryKHR(const ObjModel& model) -{ - // Building part - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Setting up the build info of the acceleration - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit - asGeom.geometry.triangles = triangles; - - - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = model.nbIndices / 3; // Nb triangles - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - return input; -} - - -//-------------------------------------------------------------------------------------------------- -// Returning the ray tracing geometry used for the BLAS, containing all spheres -// -auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj) -{ - VkDeviceAddress dataAddress = nvvk::getBufferDeviceAddress(m_device, implicitObj.implBuf.buffer); - - VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR}; - aabbs.data.deviceAddress = dataAddress; - aabbs.stride = sizeof(ObjImplicit); - - // Setting up the build info of the acceleration - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; - asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit - asGeom.geometry.aabbs = aabbs; - - - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = static_cast(implicitObj.objImpl.size()); // Nb aabb - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - return input; -} - - -void Raytracer::createBottomLevelAS(std::vector& models, ImplInst& implicitObj) -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(models.size()); - for(const auto& obj : models) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - - // Adding implicit - if(!implicitObj.objImpl.empty()) - { - auto blas = implicitToVkGeometryKHR(implicitObj); - allBlas.emplace_back(blas); - implicitObj.blasId = static_cast(allBlas.size() - 1); // remember blas ID for tlas - } - - - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR - | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR); -} - -void Raytracer::createTopLevelAS(std::vector& instances, ImplInst& implicitObj) -{ - std::vector tlas; - - - auto nbObj = static_cast(instances.size()) - 1; // minus the implicit (for material) - tlas.reserve(instances.size()); - for(uint32_t i = 0; i < nbObj; i++) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(instances[i].transform); // Position of the instance - rayInst.instanceCustomIndex = instances[i].objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(instances[i].objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - - // Add the blas containing all implicit - if(!implicitObj.objImpl.empty()) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(implicitObj.transform); // Position of the instance - rayInst.instanceCustomIndex = instances[nbObj].objIndex; - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(static_cast(implicitObj.blasId)); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 1; // We will use the same hit group for all objects (the second one) - tlas.emplace_back(rayInst); - } - - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void Raytracer::createRtDescriptorSet(const VkImageView& outputImage) -{ - using vkDSLB = VkDescriptorSetLayoutBinding; - - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL}; - - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void Raytracer::updateRtDescriptorSet(const VkImageView& outputImage) -{ - VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void Raytracer::createRtPipeline(VkDescriptorSetLayout& sceneDescLayout) -{ - - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eAnyHit, - eClosestHit1, - eAnyHit1, - eIntersect, - eCall0, - eCall1, - eCall2, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - stages[eAnyHit] = stage; - // Hit Group - 1 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit1] = stage; - // Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - stages[eAnyHit1] = stage; - // Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR; - stages[eIntersect] = stage; - - // Call0 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; - stages[eCall0] = stage; - // Call1 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; - stages[eCall1] = stage; - // Call2 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; - stages[eCall2] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - group.anyHitShader = eAnyHit; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit1; - group.anyHitShader = eAnyHit1; - group.intersectionShader = eIntersect; - m_rtShaderGroups.push_back(group); - - // Callable shaders - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - group.generalShader = eCall0; - m_rtShaderGroups.push_back(group); - group.generalShader = eCall1; - m_rtShaderGroups.push_back(group); - group.generalShader = eCall2; - m_rtShaderGroups.push_back(group); - - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR - | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); - - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void Raytracer::raytrace(const VkCommandBuffer& cmdBuf, - const glm::vec4& clearColor, - VkDescriptorSet& sceneDescSet, - VkExtent2D& size, - PushConstantRaster& sceneConstants) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = sceneConstants.lightPosition; - m_pcRay.lightIntensity = sceneConstants.lightIntensity; - m_pcRay.lightDirection = sceneConstants.lightDirection; - m_pcRay.lightSpotCutoff = sceneConstants.lightSpotCutoff; - m_pcRay.lightSpotOuterCutoff = sceneConstants.lightSpotOuterCutoff; - m_pcRay.lightType = sceneConstants.lightType; - m_pcRay.frame = sceneConstants.frame; - - - std::vector descSets{m_rtDescSet, sceneDescSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR - | VK_SHADER_STAGE_CALLABLE_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - auto& regions = m_sbtWrapper.getRegions(); - vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], size.width, size.height, 1); - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing__advance/raytrace.hpp b/ray_tracing__advance/raytrace.hpp deleted file mode 100644 index 4a5e394..0000000 --- a/ray_tracing__advance/raytrace.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/raytraceKHR_vk.hpp" -#include "nvvk/sbtwrapper_vk.hpp" -#include "obj.hpp" - -#include "shaders/host_device.h" - -class Raytracer -{ -public: - void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily); - void destroy(); - - auto objectToVkGeometryKHR(const ObjModel& model); - auto implicitToVkGeometryKHR(const ImplInst& implicitObj); - void createBottomLevelAS(std::vector& models, ImplInst& implicitObj); - void createTopLevelAS(std::vector& instances, ImplInst& implicitObj); - void createRtDescriptorSet(const VkImageView& outputImage); - void updateRtDescriptorSet(const VkImageView& outputImage); - void createRtPipeline(VkDescriptorSetLayout& sceneDescLayout); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor, VkDescriptorSet& sceneDescSet, VkExtent2D& size, PushConstantRaster& sceneConstants); - -private: - nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures - VkPhysicalDevice m_physicalDevice; - VkDevice m_device; - int m_graphicsQueueIndex{0}; - nvvk::DebugUtil m_debug; // Utility to name objects - nvvk::SBTWrapper m_sbtWrapper; - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; - - - PushConstantRay m_pcRay{}; -}; diff --git a/ray_tracing__advance/shaders/frag_shader.frag b/ray_tracing__advance/shaders/frag_shader.frag deleted file mode 100644 index 18e613d..0000000 --- a/ray_tracing__advance/shaders/frag_shader.frag +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 LightDir; - float lightIntensity; - - // Point light - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float lightDistance = length(lDir); - lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance); - LightDir = normalize(lDir); - } - else if(pcRaster.lightType == 1) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float lightDistance = length(lDir); - lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance); - LightDir = normalize(lDir); - float theta = dot(LightDir, normalize(-pcRaster.lightDirection)); - float epsilon = pcRaster.lightSpotCutoff - pcRaster.lightSpotOuterCutoff; - float spotIntensity = clamp((theta - pcRaster.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); - lightIntensity *= spotIntensity; - } - else // Directional light - { - LightDir = normalize(-pcRaster.lightDirection); - lightIntensity = 1.0; - } - - // Diffuse - vec3 diffuse = computeDiffuse(mat, LightDir, N); - - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, LightDir, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing__advance/shaders/host_device.h b/ray_tracing__advance/shaders/host_device.h deleted file mode 100644 index 4d423b5..0000000 --- a/ray_tracing__advance/shaders/host_device.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2, // Access to textures - eImplicits = 3 // Implicit objects -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - vec3 lightDirection; - float lightSpotCutoff; - float lightSpotOuterCutoff; - float lightIntensity; - int lightType; - int frame; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - uint objIndex; - vec3 lightDirection; - float lightSpotCutoff; - float lightSpotOuterCutoff; - float lightIntensity; - int lightType; - int frame; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing__advance/shaders/light_inf.rcall b/ray_tracing__advance/shaders/light_inf.rcall deleted file mode 100644 index d87c038..0000000 --- a/ray_tracing__advance/shaders/light_inf.rcall +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 core -#extension GL_EXT_ray_tracing : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "host_device.h" - -layout(location = 3) callableDataInEXT rayLight cLight; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - cLight.outLightDistance = 10000000; - cLight.outIntensity = 1.0; - cLight.outLightDir = normalize(-pcRay.lightDirection); -} diff --git a/ray_tracing__advance/shaders/light_point.rcall b/ray_tracing__advance/shaders/light_point.rcall deleted file mode 100644 index f9b3069..0000000 --- a/ray_tracing__advance/shaders/light_point.rcall +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 core -#extension GL_EXT_ray_tracing : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "host_device.h" - -layout(location = 3) callableDataInEXT rayLight cLight; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - - -void main() -{ - vec3 lDir = pcRay.lightPosition - cLight.inHitPosition; - cLight.outLightDistance = length(lDir); - cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); - cLight.outLightDir = normalize(lDir); -} diff --git a/ray_tracing__advance/shaders/light_spot.rcall b/ray_tracing__advance/shaders/light_spot.rcall deleted file mode 100644 index 0d33568..0000000 --- a/ray_tracing__advance/shaders/light_spot.rcall +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 core -#extension GL_EXT_ray_tracing : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "host_device.h" - -layout(location = 3) callableDataInEXT rayLight cLight; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - vec3 lDir = pcRay.lightPosition - cLight.inHitPosition; - cLight.outLightDistance = length(lDir); - cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); - cLight.outLightDir = normalize(lDir); - float theta = dot(cLight.outLightDir, normalize(-pcRay.lightDirection)); - float epsilon = pcRay.lightSpotCutoff - pcRay.lightSpotOuterCutoff; - float spotIntensity = clamp((theta - pcRay.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); - cLight.outIntensity *= spotIntensity; -} diff --git a/ray_tracing__advance/shaders/passthrough.vert b/ray_tracing__advance/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing__advance/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing__advance/shaders/post.frag b/ray_tracing__advance/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing__advance/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing__advance/shaders/random.glsl b/ray_tracing__advance/shaders/random.glsl deleted file mode 100644 index ef41f54..0000000 --- a/ray_tracing__advance/shaders/random.glsl +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -// Generate a random unsigned int from two unsigned int values, using 16 pairs -// of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis, -// "GPU Random Numbers via the Tiny Encryption Algorithm" -uint tea(uint val0, uint val1) -{ - uint v0 = val0; - uint v1 = val1; - uint s0 = 0; - - for(uint n = 0; n < 16; n++) - { - s0 += 0x9e3779b9; - v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); - v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); - } - - return v0; -} - -// Generate a random unsigned int in [0, 2^24) given the previous RNG state -// using the Numerical Recipes linear congruential generator -uint lcg(inout uint prev) -{ - uint LCG_A = 1664525u; - uint LCG_C = 1013904223u; - prev = (LCG_A * prev + LCG_C); - return prev & 0x00FFFFFF; -} - -// Generate a random float in [0, 1) given the previous RNG state -float rnd(inout uint prev) -{ - return (float(lcg(prev)) / float(0x01000000)); -} diff --git a/ray_tracing__advance/shaders/raycommon.glsl b/ray_tracing__advance/shaders/raycommon.glsl deleted file mode 100644 index bf8c72a..0000000 --- a/ray_tracing__advance/shaders/raycommon.glsl +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; - uint seed; - int depth; - vec3 attenuation; - int done; - vec3 rayOrigin; - vec3 rayDir; -}; - - -struct rayLight -{ - vec3 inHitPosition; - float outLightDistance; - vec3 outLightDir; - float outIntensity; -}; - -struct Implicit -{ - vec3 minimum; - vec3 maximum; - int objType; - int matId; -}; - -struct Sphere -{ - vec3 center; - float radius; -}; - -struct Aabb -{ - vec3 minimum; - vec3 maximum; -}; - -#define KIND_SPHERE 0 -#define KIND_CUBE 1 diff --git a/ray_tracing__advance/shaders/raytrace.rahit b/ray_tracing__advance/shaders/raytrace.rahit deleted file mode 100644 index cd513f2..0000000 --- a/ray_tracing__advance/shaders/raytrace.rahit +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "random.glsl" -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -// clang-format on - -void main() -{ - // Object of this instance - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - if(mat.illum != 4) - return; - - uint seed = prd.seed; // We don't want to modify the PRD - if(mat.dissolve == 0.0) - ignoreIntersectionEXT; - else if(rnd(seed) > mat.dissolve) - ignoreIntersectionEXT; -} diff --git a/ray_tracing__advance/shaders/raytrace.rchit b/ray_tracing__advance/shaders/raytrace.rchit deleted file mode 100644 index ed73d49..0000000 --- a/ray_tracing__advance/shaders/raytrace.rchit +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -layout(location = 3) callableDataEXT rayLight cLight; - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the normal at hit position - vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - // Transforming the normal to world space - normal = normalize(vec3(normal * gl_WorldToObjectEXT)); - - // Computing the coordinates of the hit position - vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - // Transforming the position to world space - worldPos = vec3(gl_ObjectToWorldEXT * vec4(worldPos, 1.0)); - - cLight.inHitPosition = worldPos; -//#define DONT_USE_CALLABLE -#if defined(DONT_USE_CALLABLE) - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - cLight.inHitPosition; - float lightDistance = length(lDir); - cLight.outIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - cLight.outLightDir = normalize(lDir); - cLight.outLightDistance = lightDistance; - } - else if(pcRay.lightType == 1) - { - vec3 lDir = pcRay.lightPosition - cLight.inHitPosition; - cLight.outLightDistance = length(lDir); - cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); - cLight.outLightDir = normalize(lDir); - float theta = dot(cLight.outLightDir, normalize(-pcRay.lightDirection)); - float epsilon = pcRay.lightSpotCutoff - pcRay.lightSpotOuterCutoff; - float spotIntensity = clamp((theta - pcRay.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); - cLight.outIntensity *= spotIntensity; - } - else // Directional light - { - cLight.outLightDir = normalize(-pcRay.lightDirection); - cLight.outIntensity = 1.0; - cLight.outLightDistance = 10000000; - } -#else - executeCallableEXT(pcRay.lightType, 3); -#endif - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, cLight.outLightDir, normal); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(normal, cLight.outLightDir) > 0) - { - float tMin = 0.001; - float tMax = cLight.outLightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = cLight.outLightDir; - uint flags = gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, cLight.outLightDir, normal); - } - } - - // Reflection - if(mat.illum == 3) - { - vec3 origin = worldPos; - vec3 rayDir = reflect(gl_WorldRayDirectionEXT, normal); - prd.attenuation *= mat.specular; - prd.done = 0; - prd.rayOrigin = origin; - prd.rayDir = rayDir; - } - - prd.hitValue = vec3(cLight.outIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing__advance/shaders/raytrace.rgen b/ray_tracing__advance/shaders/raytrace.rgen deleted file mode 100644 index 5c8d018..0000000 --- a/ray_tracing__advance/shaders/raytrace.rgen +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "random.glsl" -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - -const int NBSAMPLES = 5; - -void main() -{ - // Initialize the random number - uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame * NBSAMPLES); - prd.seed = seed; - - vec3 hitValues = vec3(0); - - for(int smpl = 0; smpl < NBSAMPLES; smpl++) - { - - float r1 = rnd(seed); - float r2 = rnd(seed); - // Subpixel jitter: send the ray through a different position inside the pixel - // each time, to provide antialiasing. - vec2 subpixel_jitter = pcRay.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2); - - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter; - - - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsNoneEXT; - float tMin = 0.001; - float tMax = 10000.0; - - prd.done = 1; - prd.rayOrigin = origin.xyz; - prd.rayDir = direction.xyz; - prd.depth = 0; - prd.hitValue = vec3(0); - prd.attenuation = vec3(1.f, 1.f, 1.f); - - for(;;) - { - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - - hitValues += prd.hitValue * prd.attenuation; - - prd.depth++; - if(prd.done == 1 || prd.depth >= 10) - break; - - origin.xyz = prd.rayOrigin; - direction.xyz = prd.rayDir; - prd.done = 1; // Will stop if a reflective material isn't hit - } - } - prd.hitValue = hitValues / NBSAMPLES; - - if(pcRay.frame == 0) - { - // First frame, replace the value in the buffer - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.f)); - } - else - { - // Do accumulation over time - float a = 1.0f / float(pcRay.frame + 1); - vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz; - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f)); - } -} diff --git a/ray_tracing__advance/shaders/raytrace.rint b/ray_tracing__advance/shaders/raytrace.rint deleted file mode 100644 index 4e654c0..0000000 --- a/ray_tracing__advance/shaders/raytrace.rint +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec3 HitAttribute; - -layout(set = 1, binding = eImplicits, scalar) buffer allImpl_ -{ - Implicit i[]; -} -allImplicits; - - -struct Ray -{ - vec3 origin; - vec3 direction; -}; - -// Ray-Sphere intersection -// http://viclw17.github.io/2018/07/16/raytracing-ray-sphere-intersection/ -float hitSphere(const Sphere s, const Ray r) -{ - vec3 oc = r.origin - s.center; - float a = dot(r.direction, r.direction); - float b = 2.0 * dot(oc, r.direction); - float c = dot(oc, oc) - s.radius * s.radius; - float discriminant = b * b - 4 * a * c; - if(discriminant < 0) - { - return -1.0; - } - else - { - return (-b - sqrt(discriminant)) / (2.0 * a); - } -} - -// Ray-AABB intersection -float hitAabb(const Aabb aabb, const Ray r) -{ - vec3 invDir = 1.0 / r.direction; - vec3 tbot = invDir * (aabb.minimum - r.origin); - vec3 ttop = invDir * (aabb.maximum - r.origin); - vec3 tmin = min(ttop, tbot); - vec3 tmax = max(ttop, tbot); - float t0 = max(tmin.x, max(tmin.y, tmin.z)); - float t1 = min(tmax.x, min(tmax.y, tmax.z)); - return t1 > max(t0, 0.0) ? t0 : -1.0; -} - -void main() -{ - - Ray ray; - ray.origin = gl_WorldRayOriginEXT; - ray.direction = gl_WorldRayDirectionEXT; - - // Sphere data - Implicit impl = allImplicits.i[gl_PrimitiveID]; - - float tHit = -1; - int hitKind = impl.objType; - if(hitKind == KIND_SPHERE) - { - Sphere sphere; - sphere.center = (impl.maximum + impl.minimum) * 0.5; - sphere.radius = impl.maximum.y - sphere.center.y; - // Sphere intersection - tHit = hitSphere(sphere, ray); - } - else - { - // AABB intersection - Aabb aabb; - aabb.minimum = impl.minimum; - aabb.maximum = impl.maximum; - tHit = hitAabb(aabb, ray); - } - - // Report hit point - if(tHit > 0) - reportIntersectionEXT(tHit, hitKind); -} diff --git a/ray_tracing__advance/shaders/raytrace.rmiss b/ray_tracing__advance/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing__advance/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing__advance/shaders/raytrace2.rahit b/ray_tracing__advance/shaders/raytrace2.rahit deleted file mode 100644 index 4200bff..0000000 --- a/ray_tracing__advance/shaders/raytrace2.rahit +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "random.glsl" -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eImplicits, scalar) buffer allImplicits_ {Implicit i[];} allImplicits; -// clang-format on - -void main() -{ - // Material of the object - Implicit impl = allImplicits.i[gl_PrimitiveID]; - - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - Materials materials = Materials(objResource.materialAddress); - - WaveFrontMaterial mat = materials.m[impl.matId]; - - if(mat.illum != 4) - return; - - uint seed = prd.seed; // We don't want to modify the PRD - if(mat.dissolve == 0.0) - ignoreIntersectionEXT; - else if(rnd(seed) > mat.dissolve) - ignoreIntersectionEXT; -} diff --git a/ray_tracing__advance/shaders/raytrace2.rchit b/ray_tracing__advance/shaders/raytrace2.rchit deleted file mode 100644 index 187f02f..0000000 --- a/ray_tracing__advance/shaders/raytrace2.rchit +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; - - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eImplicits, scalar) buffer allImplicits_ {Implicit i[];} allImplicits; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -layout(location = 3) callableDataEXT rayLight cLight; - - -void main() -{ - vec3 worldPos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - - Implicit impl = allImplicits.i[gl_PrimitiveID]; - - // Computing the normal at hit position - vec3 normal; - if(gl_HitKindEXT == KIND_SPHERE) - { - vec3 center = (impl.maximum + impl.minimum) * 0.5; - normal = normalize(worldPos - center); - } - else if(gl_HitKindEXT == KIND_CUBE) - { - const float epsilon = 0.00001; - if(abs(impl.maximum.x - worldPos.x) < epsilon) - normal = vec3(1, 0, 0); - else if(abs(impl.maximum.y - worldPos.y) < epsilon) - normal = vec3(0, 1, 0); - else if(abs(impl.maximum.z - worldPos.z) < epsilon) - normal = vec3(0, 0, 1); - else if(abs(impl.minimum.x - worldPos.x) < epsilon) - normal = vec3(-1, 0, 0); - else if(abs(impl.minimum.y - worldPos.y) < epsilon) - normal = vec3(0, -1, 0); - else if(abs(impl.minimum.z - worldPos.z) < epsilon) - normal = vec3(0, 0, -1); - } - - cLight.inHitPosition = worldPos; - executeCallableEXT(pcRay.lightType, 3); - - // Material of the object - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - Materials materials = Materials(objResource.materialAddress); - WaveFrontMaterial mat = materials.m[impl.matId]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, cLight.outLightDir, normal); - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(normal, cLight.outLightDir) > 0) - { - float tMin = 0.001; - float tMax = cLight.outLightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = cLight.outLightDir; - uint flags = gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, cLight.outLightDir, normal); - } - } - - // Reflection - if(mat.illum == 3) - { - vec3 origin = worldPos; - vec3 rayDir = reflect(gl_WorldRayDirectionEXT, normal); - prd.attenuation *= mat.specular; - prd.done = 0; - prd.rayOrigin = origin; - prd.rayDir = rayDir; - } - - - prd.hitValue = vec3(cLight.outIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing__advance/shaders/raytraceShadow.rmiss b/ray_tracing__advance/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing__advance/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing__advance/shaders/vert_shader.vert b/ray_tracing__advance/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing__advance/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing__advance/shaders/wavefront.glsl b/ray_tracing__advance/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing__advance/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing__before/CMakeLists.txt b/ray_tracing__before/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing__before/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing__before/README.md b/ray_tracing__before/README.md deleted file mode 100644 index 4056d5f..0000000 --- a/ray_tracing__before/README.md +++ /dev/null @@ -1,142 +0,0 @@ -# NVIDIA Vulkan Ray Tracing Tutorial - -This sample is a simple OBJ viewer in Vulkan, without any ray tracing functionality. -It is the starting point of the [ray tracing tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html), -the source of the application where ray tracing will be added. -![](images/vk_ray_tracing__before.png) - -Before starting the tutorial and adding what is necessary to enable ray tracing, here is a brief description of how this basic example was created. -## Structure - -* main.cpp : creates a Vulkan context, call for loading OBJ files, drawing loop -* hello_vulkan.[cpp|h]: example class that loads and store OBJ in Vulkan buffers, load textures, creates pipelines and render the scene -* [nvvk](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk): library of independent Vulkan helpers. - -## Overview - -The following describes the function calls in main(). The helpers will not be described here, but following the link should give more details on how they work. - -### Window and Vulkan Setup - -* Creates a window using [GLFW](https://www.glfw.org/). -* Creates a Vulkan context using the [`nvvk::Context`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#context_vkhpp) - helper. The result is a `VkInstance`, `VkDevice`, `VkPhisicalDevice`, the queues and the extensions initialized. - * The window was created, but not the surface to draw in this window. This is done using the information from `VkInstance` and `GLFWwindow`. The - `VkSurfaceKHR` will be used to find the proper queue. - -### Sample Setup - -* Hello vulkan setup: - * [base] Keep a copy of `VkInstance`, `VkDevice`, `VkPhysicalDevice` and graphics Queue Index. - * [base] Create a command pool - * Initialize the [Vulkan resource allocator](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#resourceallocator_vkhpp) (nvvk::alloc). -* Create Swapchain [base]: - * Using the base class method and the help of [`nvvk::Swapchain`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#swapchain_vkhpp), - initialize the swapchain for rendering onto the surface. - * Finds the surface color and depth format. - * Create *n* `VkFence` for synchronization. -* Create depth buffer [base]: depth buffer image with the format query in the swapchain -* Create render pass [base]: - * Simple render pass, with two attachments: color and depth - * Using swapchain color and depth format. -* Create frame buffers [base]: - * Create *n images* of the number returned by the swapchain - * Create as many frame buffers and attach the images -* Initialize GUI [base]: we are using [Dear ImGui](https://github.com/ocornut/imgui) and - this is doing the initialization for Vulkan. -* Loading [Wavefront .obj file](https://en.wikipedia.org/wiki/Wavefront_.obj_file): - * This is a very simple format, but it allows us to make manual modifications in the file, to load several .obj files and to combine them to obtain a more complex scene. We can also easily create several instances of the loaded objects. - * Loading the .obj is done through the [ObjLoader](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/blob/3e399adf0a3e991795fbdf91e0e6c23b9f492bb8/common/obj_loader.cpp#L26) which is using [tinyobjloader](https://github.com/tinyobjloader/tinyobjloader). - * All vertices are in the form of: position, normal, color, texture coordinates - * Every 3 vertex indices are creating a triangle. - * Every triangle has an index of the material it is using. - * There are M materials and T textures. - * We allocate buffers and staging the transfer to the GPU using our resource allocator. - * We create an instance of the loaded model. - * :warning: We keep the addresses of the created buffers and append this to a vector of `ObjDesc`, which allows easy access to the model information from a shader. - -### Offscreen image & Graphic Pipeline - -We have a swapchain and window frame buffers, but we will not render the scene directly to them. Instead, we will render to an RGBA32F image, and then render that image to a full screen triangle using a tone mapper. We could have rendered directly to one of the swapchain framebuffers and applied a tone mapper, but this separation will be very useful for rendering G-Buffers and doing something similar with ray tracing. - -* Create offscreen render: - * Create a color and depth image, format are VK_FORMAT_R32G32B32A32_SFLOAT and best depth for the physical device using [`nvvk::findDepthFormat`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#renderpasses_vkhpp). - * Create a render pass to render using those images [`nvvk::createRenderPass`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#renderpasses_vkhpp). - * Create a frame buffer, to use as a target when rendering offline. -* Create descriptor set layout: - * Using the [`nvvk::DescriptorSetBindings`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#class-nvvkdescriptorsetbindings), describing the resources that will be used in the vertex and fragment shader. -* Create graphic pipeline: - * Using [`nvvk::GraphicsPipelineGeneratorCombined`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#class-nvvkgraphicspipelinegeneratorcombined) - * Load both vertex and fragment SpirV shaders - * Describe the vertex attributes: pos, nrm, color, uv -* Create uniform buffer: - * The uniform buffer is holding global scene information and is updated at each frame. - * The information in this sample consist of camera matrices and will be - updated in the drawing loop using `updateUniformBuffer()`. -* Create Obj description buffer: - * When loading .obj, we stored the addresses of the OBJ buffers. - * If we have loaded many .obj, the array will be as large as the number of obj loaded. - * Each instance has the index of the OBJ, therefore the information of the model will be easily retrievable in the shader. - * This function creates the buffer holding the vector of `ObjDesc`. -* Update descriptor set: - * The descriptor set has been created, but here we are writing the information, meaning all the buffers and textures we have created. - -At this point, the OBJs are loaded and their information is uploaded to the GPU. The graphic pipeline and the information describing the resources are also created. - -### Post Pipeline - -We need to create a "post pipeline". This is specific to the raster of this sample. As mentioned before, we render in a full screen triangle, the result of the raster and apply a tonemapper. This step will be rendered directly into the framebuffer of the swapchain. - -![](images/base_pipeline.png) - -* Create post descriptor: - * Adding the image input (result of rendering) -* Create post pipeline: - * Passtrough vertex shader (full screen triangle) - * Fragment tone-mapper shader -* Update post descriptor: - * Writing the image (RGB32F) address - -At this point we are ready to start the rendering loop. - -* Setup Glfw callback: - * Our base class has many functions to react on Glfw, such as change of window size, mouse and keyboard inputs. - * All callback functions are virtual, which allow to override the base functionality, but for most there isn't anything to do. - * Except for `onResize`, since we render to an intermediate image (RGB32F), this image will need to be re-created with the new size and the post pipeline will need the address of this image. Therefore, there is an overload of this function. - -### Rendering Loop - -* Render indefinitely until Glfw receive a close action -* Glfw pulling events -* Imgui new frame and rendering (not drawing) -* Prepare Frame - * This is part of the swapchain, we can have a double or triple buffer and - this call will be waiting (fence) to make sure that one swapchain frame buffer - is available. -* Get current frame - * Depending if we have a double or triple buffer, it will return: 0 or 1, or 0, 1 or 2. - * Resources in the base class exist in that amount: color images, frame buffer, command buffer, fence -* Get the command buffer for the current frame (better to re-use command buffers than creating new ones) -* Update the uniform buffer: - * Push the current camera matrices - -#### Offscreen - -* Start offscreen rendering pass - * We will be rendering (raster) in the RGBA32F image using the offscreen render pass and frame buffer. -* Rasterize - * This is rasterizing the entire scene, all instances of each object. - -#### Final - -Start another rendering, this time in the swapchain frame buffer - -* Use the base class render pass -* Use the swapchain frame buffer -* Render a full-screen triangle with the raster image and tone-mapping it. -* Actually rendering Imgui in Vulkan -* Submit the frame for execution and display - -### Clean up - -The rest is clean up all allocations diff --git a/ray_tracing__before/hello_vulkan.cpp b/ray_tracing__before/hello_vulkan.cpp deleted file mode 100644 index d59e550..0000000 --- a/ray_tracing__before/hello_vulkan.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | flag); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | flag); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing__before/hello_vulkan.h b/ray_tracing__before/hello_vulkan.h deleted file mode 100644 index b574299..0000000 --- a/ray_tracing__before/hello_vulkan.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; -}; diff --git a/ray_tracing__before/images/base_pipeline.png b/ray_tracing__before/images/base_pipeline.png deleted file mode 100644 index 19c8a85..0000000 Binary files a/ray_tracing__before/images/base_pipeline.png and /dev/null differ diff --git a/ray_tracing__before/images/vk_ray_tracing__before.png b/ray_tracing__before/images/vk_ray_tracing__before.png deleted file mode 100644 index a7eedfc..0000000 Binary files a/ray_tracing__before/images/vk_ray_tracing__before.png and /dev/null differ diff --git a/ray_tracing__before/main.cpp b/ray_tracing__before/main.cpp deleted file mode 100644 index b82db1c..0000000 --- a/ray_tracing__before/main.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing__before/shaders/frag_shader.frag b/ray_tracing__before/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing__before/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing__before/shaders/host_device.h b/ray_tracing__before/shaders/host_device.h deleted file mode 100644 index a22192e..0000000 --- a/ray_tracing__before/shaders/host_device.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing__before/shaders/passthrough.vert b/ray_tracing__before/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing__before/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing__before/shaders/post.frag b/ray_tracing__before/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing__before/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing__before/shaders/vert_shader.vert b/ray_tracing__before/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing__before/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing__before/shaders/wavefront.glsl b/ray_tracing__before/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing__before/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing__simple/CMakeLists.txt b/ray_tracing__simple/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing__simple/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing__simple/README.md b/ray_tracing__simple/README.md deleted file mode 100644 index 89a877c..0000000 --- a/ray_tracing__simple/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# NVIDIA Vulkan Ray Tracing Tutorial - -This example is the result of the ray tracing tutorial. -The tutorial is adding ray tracing capability to an OBJ rasterizer in Vulkan - -If you haven't done it, [**Start Ray Tracing Tutorial**](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -![resultRaytraceShadowMedieval](../docs/Images/resultRaytraceShadowMedieval.png) - -## Going Further - -Once the tutorial completed and the basics of ray tracing are in place, other tuturials are going further from this code base. - -See all other [additional ray tracing tutorials](../README.md#extra-tutorials) diff --git a/ray_tracing__simple/files/shaders.zip b/ray_tracing__simple/files/shaders.zip deleted file mode 100644 index 7d3036c..0000000 Binary files a/ray_tracing__simple/files/shaders.zip and /dev/null differ diff --git a/ray_tracing__simple/files/shadowShaders.zip b/ray_tracing__simple/files/shadowShaders.zip deleted file mode 100644 index f624461..0000000 Binary files a/ray_tracing__simple/files/shadowShaders.zip and /dev/null differ diff --git a/ray_tracing__simple/hello_vulkan.cpp b/ray_tracing__simple/hello_vulkan.cpp deleted file mode 100644 index 098c64d..0000000 --- a/ray_tracing__simple/hello_vulkan.cpp +++ /dev/null @@ -1,936 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - m_alloc.destroy(m_rtSBTBuffer); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - - // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. - if(m_rtProperties.maxRayRecursionDepth <= 1) - { - throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); - } - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// The Shader Binding Table (SBT) -// - getting all shader handles and write them in a SBT buffer -// - Besides exception, this could be always done like this -// -void HelloVulkan::createRtShaderBindingTable() -{ - uint32_t missCount{2}; - uint32_t hitCount{1}; - auto handleCount = 1 + missCount + hitCount; - uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - - // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. - uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); - - m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member - m_missRegion.stride = handleSizeAligned; - m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_hitRegion.stride = handleSizeAligned; - m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - - // Get the shader group handles - uint32_t dataSize = handleCount * handleSize; - std::vector handles(dataSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); - assert(result == VK_SUCCESS); - - // Allocate a buffer for storing the SBT. - VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. - - // Find the SBT addresses of each group - VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; - VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - m_rgenRegion.deviceAddress = sbtAddress; - m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; - m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; - - // Helper to retrieve the handle data - auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; - - // Map the SBT buffer and write in the handles. - auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); - uint8_t* pData{nullptr}; - uint32_t handleIdx{0}; - // Raygen - pData = pSBTBuffer; - memcpy(pData, getHandle(handleIdx++), handleSize); - // Miss - pData = pSBTBuffer + m_rgenRegion.size; - for(uint32_t c = 0; c < missCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_missRegion.stride; - } - // Hit - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; - for(uint32_t c = 0; c < hitCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_hitRegion.stride; - } - - m_alloc.unmap(m_rtSBTBuffer); - m_alloc.finalizeAndReleaseStaging(); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); - - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing__simple/hello_vulkan.h b/ray_tracing__simple/hello_vulkan.h deleted file mode 100644 index e1c9a6e..0000000 --- a/ray_tracing__simple/hello_vulkan.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - - nvvk::Buffer m_rtSBTBuffer; - VkStridedDeviceAddressRegionKHR m_rgenRegion{}; - VkStridedDeviceAddressRegionKHR m_missRegion{}; - VkStridedDeviceAddressRegionKHR m_hitRegion{}; - VkStridedDeviceAddressRegionKHR m_callRegion{}; - - // Push constant for ray tracer - PushConstantRay m_pcRay{}; -}; diff --git a/ray_tracing__simple/main.cpp b/ray_tracing__simple/main.cpp deleted file mode 100644 index 876cfc5..0000000 --- a/ray_tracing__simple/main.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - helloVk.createRtShaderBindingTable(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing__simple/shaders/frag_shader.frag b/ray_tracing__simple/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing__simple/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing__simple/shaders/host_device.h b/ray_tracing__simple/shaders/host_device.h deleted file mode 100644 index a22192e..0000000 --- a/ray_tracing__simple/shaders/host_device.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing__simple/shaders/passthrough.vert b/ray_tracing__simple/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing__simple/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing__simple/shaders/post.frag b/ray_tracing__simple/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing__simple/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing__simple/shaders/raycommon.glsl b/ray_tracing__simple/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing__simple/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing__simple/shaders/raytrace.rchit b/ray_tracing__simple/shaders/raytrace.rchit deleted file mode 100644 index 2eb634e..0000000 --- a/ray_tracing__simple/shaders/raytrace.rchit +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing__simple/shaders/raytrace.rgen b/ray_tracing__simple/shaders/raytrace.rgen deleted file mode 100644 index 4b8edad..0000000 --- a/ray_tracing__simple/shaders/raytrace.rgen +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "host_device.h" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0)); -} diff --git a/ray_tracing__simple/shaders/raytrace.rmiss b/ray_tracing__simple/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing__simple/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing__simple/shaders/raytraceShadow.rmiss b/ray_tracing__simple/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing__simple/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing__simple/shaders/vert_shader.vert b/ray_tracing__simple/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing__simple/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing__simple/shaders/wavefront.glsl b/ray_tracing__simple/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing__simple/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_advanced_compilation/CMakeLists.txt b/ray_tracing_advanced_compilation/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_advanced_compilation/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_advanced_compilation/README.md b/ray_tracing_advanced_compilation/README.md deleted file mode 100644 index 7b97c0a..0000000 --- a/ray_tracing_advanced_compilation/README.md +++ /dev/null @@ -1,277 +0,0 @@ -# Advanced Compilation - -![](images/advanced_compilation.png) - -The simplest way of defining ray tracing pipelines is by using monolithic `VkRayTracingPipelineCreateInfoKHR` structures specifying the pipeline stages and shader groups. Even if pipelines share some stages, they are compiled separately. Furthermore, by default `vkCreateRayTracingPipelinesKHR` blocks the current thread until completion: -![](images/high_level_regular_compilation.png) - - However, when using multiple pipelines, some of them may have some shader stages in common. Large pipelines may also take a long time to compile on a single thread. - -This sample introduces the [VK_KHR_pipeline_library](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_library.html) extension to create shader libraries that can be separately compiled and reused in ray tracing pipelines. The compilation of the final pipeline is carried out on multiple threads using the [VK_KHR_deferred_host_operations](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_deferred_host_operations.html) extension. - -The code below is based on the [`ray_tracing_specialization`](../ray_tracing_specialization) sample, which introduces compile-time variations of a hit shader. - -## Pipeline Library - -Using monolithic pipeline definitions all stages are compiled for each pipeline, regardless of potential reuse. The shader groups are then referenced in the Shader Binding Table using their indices: -![](images/regular_pipeline.png) - -Pipeline libraries are `VkPipeline` objects that cannot be bound directly. Instead, they can be compiled once and linked into as many pipelines as necessary. The Shader Binding Table of the resulting pipeline references the shader groups of the library as if they had been appended to the groups and stages in the main `VkRayTracingPipelineCreateInfo` -![](images/library.png) - -We start by adding the device extension in main() - -~~~~ C - contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); -~~~~ - -Following by adding a new member in the `HelloVulkan` class: - -~~~~ C - // Ray tracing shader library - VkPipeline m_rtShaderLibrary; -~~~~ - -In `HelloVulkan::createRtPipeline()` the `StageIndices` enumeration describes the indices of the stages defined in the pipeline creation structure. The hit groups will be moved to our library, hence we remove them from the enumeration: - -~~~~ C - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eShaderGroupCount - }; -~~~~ - -The shader modules will be referenced partly in the main pipeline, and partly in the pipeline library. To ensure proper deletion of the modules after use, we will store their handles in - -~~~~ C - // Store the created modules for later cleanup - std::vector modules; -~~~~ - -Then, after each call to `nvvk::createShaderModule` we store the resulting module: - -~~~~ C - modules.push_back(stage.module); -~~~~ - -The specialization constants sample creates one shader module per specialization. Instead, we load that module once and reuse it for each specialization. Those specializations are then stored in the stages of the pipeline library: - -~~~~ C - // Hit Group - Closest Hit - // Create many variation of the closest hit - stage.module = nvvk::createShaderModule( - m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - modules.push_back(stage.module); - // Store the hit groups for compilation in a separate pipeline library object - std::vector libraryStages{}; - for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) - { - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stage.pSpecializationInfo = specializations[s].getSpecialization(); - libraryStages.push_back(stage); - } -~~~~ - -Similarly, the hit groups will be stored in the library by replacing the storage of the hit groups in `m_rtShaderGroups` by: - -~~~~ C - // Shader groups for the pipeline library containing the closest hit shaders - std::vector libraryShaderGroups; - - VkRayTracingShaderGroupCreateInfoKHR libraryGroup{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - libraryGroup.anyHitShader = VK_SHADER_UNUSED_KHR; - libraryGroup.closestHitShader = VK_SHADER_UNUSED_KHR; - libraryGroup.generalShader = VK_SHADER_UNUSED_KHR; - libraryGroup.intersectionShader = VK_SHADER_UNUSED_KHR; - libraryGroup.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - - // Hit Group - Closest Hit + AnyHit - // Creating many Hit groups, one for each specialization - for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) - { - // The indices of the stages are local to the pipeline library - libraryGroup.closestHitShader = s; // Using variation of the closest hit - libraryShaderGroups.push_back(libraryGroup); - } -~~~~ - -It is important to note that the stage indices are local to the pipeline library, regardless of where they will be used in the final pipeline. Those indices will be later offset depending on the contents of the pipeline. - -Once the groups and stages are defined we can create the pipeline library. After the creation of the ray tracing pipeline layout, we define the base of the library creation information: - -~~~~ C - // Creation of the pipeline library object - VkRayTracingPipelineCreateInfoKHR pipelineLibraryInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - // Flag the object as a pipeline library, which is a specific object that cannot be used directly. - pipelineLibraryInfo.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; - // Use the same layout as the target pipeline - pipelineLibraryInfo.layout = m_rtPipelineLayout; - // As for the interface the maximum recursion depth must also be consistent across the pipeline - pipelineLibraryInfo.maxPipelineRayRecursionDepth = 2; -~~~~ - -Pipeline libraries are technically independent from the pipeline they will be linked into. However, linking can only be achieved by enforcing strong consistency constraints, such as having the same pipeline layout and maximum recursion depth. If the recursion depth differs the compilation of the final pipeline will fail. - -In addition, the pipeline libraries need to have the same pipeline interface. This interface defines the maximum amount of data passed across stages: - -~~~~ C - // Pipeline libraries need to define an interface, defined by the maximum hit attribute size (typically 2 for - // the built-in triangle intersector) and the maximum payload size (3 floating-point values in this sample). - // Pipeline libraries can be linked into a final pipeline only if their interface matches - VkRayTracingPipelineInterfaceCreateInfoKHR pipelineInterface{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR}; - pipelineInterface.maxPipelineRayHitAttributeSize = sizeof(glm::vec2); - pipelineInterface.maxPipelineRayPayloadSize = sizeof(glm::vec3); - pipelineLibraryInfo.pLibraryInterface = &pipelineInterface; -~~~~ - -Finally we provide the stage and shader groups information to the library creation information, and create the pipeline library in the same way as any other pipeline: - -~~~~ C - // Shader groups and stages for the library - pipelineLibraryInfo.groupCount = static_cast(libraryShaderGroups.size()); - pipelineLibraryInfo.pGroups = libraryShaderGroups.data(); - pipelineLibraryInfo.stageCount = static_cast(libraryStages.size()); - pipelineLibraryInfo.pStages = libraryStages.data(); - - // Creation of the pipeline library - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &pipelineLibraryInfo, nullptr, &m_rtShaderLibrary); -~~~~ - -The pipeline library is now created, but the application cannot run yet: we still need to indicate that the final pipeline will link with our library. Before calling `vkCreateRayTracingPipelinesKHR` for the final pipeline, we insert the reference to the library: - -~~~~ C - // The library will be linked into the final pipeline by specifying its handle and shared interface - VkPipelineLibraryCreateInfoKHR inputLibrary{VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR}; - inputLibrary.libraryCount = 1; - inputLibrary.pLibraries = &m_rtShaderLibrary; - rayPipelineInfo.pLibraryInfo = &inputLibrary; - rayPipelineInfo.pLibraryInterface = &pipelineInterface; -~~~~ - -The pipeline is now built from the specified shader groups and stages as well as the library containing the hit groups. The groups and stages are linked together using indices, and indices are local to each library. To avoid collisions the pipeline creation will consider the stages of the libraries as if they had been appended to the stage list of the original `VkRayTracingPipelineCreateInfoKHR`, in the order in which the libraries are defined in `pLibraries`. - -Therefore, the Shader Binding Table needs to be updated accordingly, by making the wrapper aware of the contents of the library: - -~~~~ C - // The Shader Binding Table is built accounting for the entire pipeline, including the - // stages contained in the library. Passing the library information allows the wrapper - // to shift the shader group indices accordingly - m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo, {pipelineLibraryInfo}); -~~~~ - -At the end of the function we destroy the shader modules using our vector of modules instead of iterating over the stages of the main pipeline: - -~~~~ C - // Destroy all the created modules, for both libraries and main pipeline - for(auto& m : modules) - vkDestroyShaderModule(m_device, m, nullptr); -~~~~ - -The pipeline library has the same lifetime as the pipeline that uses it. The final step of this Section is the destruction of the library in the `HelloVulkan::destroy()` method: - -~~~~ C - // Pipeline libraries have the same lifetime as the pipelines that uses them - vkDestroyPipeline(m_device, m_rtShaderLibrary, nullptr); -~~~~ - -As an exercise, it is possible to create another library containing the other shader stages, and link those libraries together into the pipeline. - -## Parallel Compilation Using Deferred Host Operations - -By default pipelines compilations are blocking the calling thread until completion: - ![Pipeline compilation on a single thread](images/single_threaded_compilation.png) - -Ray tracing pipelines are often complex, and can benefit from multithreaded compilation. This can drastically reduce the compilation times of complex pipelines. The deferred host operations extension allows the work involved in `vkCreateRayTracingPipelinesKHR` to be split into multiple threads provided by the application: - ![Deferred Host Operations use app-provided threads to parallelize the compilation](images/deferred_host_operations.png) - -We start by including the support of C++ threading using `std::async` at the beginning of the source file: - -~~~~ C -#include -~~~~ - -In this sample we will distribute the compilation of the final ray tracing pipeline using a `VkDeferredOperation`, created just before calling `vkCreateRayTracingPipelinesKHR`: - -~~~~ C - // Deferred operations allow the driver to parallelize the pipeline compilation on several threads - // Create a deferred operation - VkDeferredOperationKHR deferredOperation; - VkResult result = vkCreateDeferredOperationKHR(m_device, nullptr, &deferredOperation); - assert(result == VK_SUCCESS); -~~~~ - -Then we modify the pipeline creation to indicate we defer the operation: - -~~~~ C - // The pipeline creation is called with the deferred operation. Instead of blocking until - // the compilation is done, the call returns immediately - vkCreateRayTracingPipelinesKHR(m_device, deferredOperation, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); -~~~~ - -Instead of immediately launching the compilation and blocking execution until completion, this call will return immediately with value `VK_OPERATION_DEFERRED_KHR` if deferred operations are supported by the system. - -Threading control is left to the application. Therefore, our application will allocate a number of threads for compilation: - -~~~~ C - // The compilation will be split into a maximum of 8 threads, or the maximum supported by the - // driver for that operation - uint32_t maxThreads{8}; - uint32_t threadCount = std::min(vkGetDeferredOperationMaxConcurrencyKHR(m_device, deferredOperation), maxThreads); -~~~~ - -We then launch those threads using `std::async`: - -~~~~ C - std::vector> joins; - for(uint32_t i = 0; i < threadCount; i++) - { - VkDevice device{m_device}; - joins.emplace_back(std::async(std::launch::async, [device, deferredOperation]() { - // Wait until the thread has finished its work - VkResult result = vkDeferredOperationJoinKHR(device, deferredOperation); - // A return value of SUCCESS means the pipeline compilation is done. - // THREAD_DONE indicates that thread has no work to do for this task - // (e.g. the operation could not be split into that many threads) - // THREAD_IDLE indicates the thread has finished its task, but the overall pipeline - // compilation is not finished. - // In the last two cases, more work could be performed by the thread, such as waiting - // for another deferred operation - assert(result == VK_SUCCESS || result == VK_THREAD_DONE_KHR || result == VK_THREAD_IDLE_KHR); - })); - } -~~~~ - -Each thread executes a blocking function taking care of a subset of the compilation. When a thread has finished its task, the pipeline compilation may be complete (`VK_SUCCESS`) or there may be no more work for this thread. In this case one could consider executing more work using those threads, such as compiling another pipeline. - -Since there is only one pipeline to compile, we wait for all threads to finish and check whether the pipeline compilation succeeded: - -~~~~ C - // Wait for all threads to finish - for(auto& f : joins) - { - f.get(); - } - // Once the deferred operation is complete, check for compilation success - result = vkGetDeferredOperationResultKHR(m_device, deferredOperation); - assert(result == VK_SUCCESS); -~~~~ - -Once the compilation is finished we can destroy the deferred operation: - -~~~~ C - // Destroy the deferred operation - vkDestroyDeferredOperationKHR(m_device, deferredOperation, nullptr); -~~~~ - -Congratulations! The ray tracing pipeline is now built using explicit stages and a pipeline library, and the final compilation is executed on multiple threads. As an exercise, the pipeline library described at the beginning of this tutorial can also be compiled in parallel. -This approach can be extended to compile multiple pipelines sharing some components using multiple threads: -![](images/high_level_advanced_compilation.png) - -## References - -* [VK_KHR_pipeline_library](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_library.html) -* [VK_KHR_deferred_host_operations](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_deferred_host_operations.html) diff --git a/ray_tracing_advanced_compilation/hello_vulkan.cpp b/ray_tracing_advanced_compilation/hello_vulkan.cpp deleted file mode 100644 index 0e0fd93..0000000 --- a/ray_tracing_advanced_compilation/hello_vulkan.cpp +++ /dev/null @@ -1,1027 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" -// Support for C++ multithreading -#include - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_sbtWrapper.destroy(); - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - // Pipeline libraries have the same lifetime as the pipelines that uses them - vkDestroyPipeline(m_device, m_rtShaderLibrary, nullptr); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); - m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -////////////////////////////////////////////////////////////////////////// -// Helper to generate specialization info -// -class Specialization -{ -public: - void add(uint32_t constantID, int32_t value) - { - spec_values.push_back(value); - VkSpecializationMapEntry entry; - entry.constantID = constantID; - entry.size = sizeof(int32_t); - entry.offset = static_cast(spec_entries.size() * sizeof(int32_t)); - spec_entries.emplace_back(entry); - } - - void add(const std::vector>& const_values) - { - for(const auto& v : const_values) - add(v.first, v.second); - } - - VkSpecializationInfo* getSpecialization() - { - spec_info.dataSize = static_cast(spec_values.size() * sizeof(int32_t)); - spec_info.pData = spec_values.data(); - spec_info.mapEntryCount = static_cast(spec_entries.size()); - spec_info.pMapEntries = spec_entries.data(); - return &spec_info; - } - -private: - std::vector spec_values; - std::vector spec_entries; - VkSpecializationInfo spec_info{}; -}; - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eShaderGroupCount - }; - - // Specialization - set 8 permutations of the 3 constant - std::vector specializations(8); - for(int i = 0; i < 8; i++) - { - int a = ((i >> 2) % 2) == 1; - int b = ((i >> 1) % 2) == 1; - int c = ((i >> 0) % 2) == 1; - specializations[i].add({{0, a}, {1, b}, {2, c}}); - } - - - // All stages - // Store the created modules for later cleanup - std::vector modules; - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - modules.push_back(stage.module); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - modules.push_back(stage.module); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - modules.push_back(stage.module); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - - // Hit Group - Closest Hit - // Create many variation of the closest hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - - modules.push_back(stage.module); - // Store the hit groups for compilation in a separate pipeline library object - std::vector libraryStages{}; - for(auto& specialization : specializations) - { - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stage.pSpecializationInfo = specialization.getSpecialization(); - libraryStages.push_back(stage); - } - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // Shader groups for the pipeline library containing the closest hit shaders - std::vector libraryShaderGroups; - - VkRayTracingShaderGroupCreateInfoKHR libraryGroup{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - libraryGroup.anyHitShader = VK_SHADER_UNUSED_KHR; - libraryGroup.closestHitShader = VK_SHADER_UNUSED_KHR; - libraryGroup.generalShader = VK_SHADER_UNUSED_KHR; - libraryGroup.intersectionShader = VK_SHADER_UNUSED_KHR; - libraryGroup.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - - // Hit Group - Closest Hit + AnyHit - // Creating many Hit groups, one for each specialization - - for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) - { - // The indices of the stages are local to the pipeline library - libraryGroup.closestHitShader = s; // Using variation of the closest hit - libraryShaderGroups.push_back(libraryGroup); - } - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - // Creation of the pipeline library object - VkRayTracingPipelineCreateInfoKHR pipelineLibraryInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - // Flag the object as a pipeline library, which is a specific object that cannot be used directly. - pipelineLibraryInfo.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; - // Use the same layout as the target pipeline - pipelineLibraryInfo.layout = m_rtPipelineLayout; - // As for the interface the maximum recursion depth must also be consistent across the pipeline - pipelineLibraryInfo.maxPipelineRayRecursionDepth = 2; - - // Pipeline libraries need to define an interface, defined by the maximum hit attribute size (typically 2 for - // the built-in triangle intersector) and the maximum payload size (3 floating-point values in this sample). - // Pipeline libraries can be linked into a final pipeline only if their interface matches - VkRayTracingPipelineInterfaceCreateInfoKHR pipelineInterface{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR}; - pipelineInterface.maxPipelineRayHitAttributeSize = sizeof(glm::vec2); - pipelineInterface.maxPipelineRayPayloadSize = sizeof(glm::vec3); - pipelineLibraryInfo.pLibraryInterface = &pipelineInterface; - - // Shader groups and stages for the library - pipelineLibraryInfo.groupCount = static_cast(libraryShaderGroups.size()); - pipelineLibraryInfo.pGroups = libraryShaderGroups.data(); - pipelineLibraryInfo.stageCount = static_cast(libraryStages.size()); - pipelineLibraryInfo.pStages = libraryStages.data(); - - // Creation of the pipeline library - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &pipelineLibraryInfo, nullptr, &m_rtShaderLibrary); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - // The library will be linked into the final pipeline by specifying its handle and shared interface - VkPipelineLibraryCreateInfoKHR inputLibrary{VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR}; - inputLibrary.libraryCount = 1; - inputLibrary.pLibraries = &m_rtShaderLibrary; - rayPipelineInfo.pLibraryInfo = &inputLibrary; - rayPipelineInfo.pLibraryInterface = &pipelineInterface; - - // Deferred operations allow the driver to parallelize the pipeline compilation on several threads - // Create a deferred operation - VkDeferredOperationKHR hOp; - VkResult result = vkCreateDeferredOperationKHR(m_device, nullptr, &hOp); - assert(result == VK_SUCCESS); - - // The pipeline creation is called with the deferred operation. Instead of blocking until - // the compilation is done, the call returns immediately - vkCreateRayTracingPipelinesKHR(m_device, hOp, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - // The compilation will be split into a maximum of 8 threads, or the maximum supported by the - // driver for that operation - uint32_t maxThreads{8}; - uint32_t threadCount = std::min(vkGetDeferredOperationMaxConcurrencyKHR(m_device, hOp), maxThreads); - - - std::vector> joins; - for(uint32_t i = 0; i < threadCount; i++) - { - VkDevice device{m_device}; - joins.emplace_back(std::async(std::launch::async, [device, hOp]() { - // Wait until the thread has finished its work - VkResult result = vkDeferredOperationJoinKHR(device, hOp); - // A return value of SUCCESS means the pipeline compilation is done. - // THREAD_DONE indicates that thread has no work to do for this task - // (e.g. the operation could not be split into that many threads) - // THREAD_IDLE indicates the thread has finished its task, but the overall pipeline - // compilation is not finished. - // In the last two cases, more work could be performed by the thread, such as waiting - // for another deferred operation - assert(result == VK_SUCCESS || result == VK_THREAD_DONE_KHR || result == VK_THREAD_IDLE_KHR); - })); - } - // Wait for all threads to finish - for(auto& f : joins) - { - f.get(); - } - // Once the deferred operation is complete, check for compilation success - result = vkGetDeferredOperationResultKHR(m_device, hOp); - assert(result == VK_SUCCESS); - // Destroy the deferred operation - vkDestroyDeferredOperationKHR(m_device, hOp, nullptr); - - // The Shader Binding Table is built accounting for the entire pipeline, including the - // stages contained in the library. Passing the library information allows the wrapper - // to shift the shader group indices accordingly - m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo, {pipelineLibraryInfo}); - - // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. - if(m_rtProperties.maxRayRecursionDepth <= 1) - { - throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); - } - - // Destroy all the created modules, for both libraries and main pipeline - for(auto& m : modules) - vkDestroyShaderModule(m_device, m, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - auto& regions = m_sbtWrapper.getRegions(); - vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing_advanced_compilation/hello_vulkan.h b/ray_tracing_advanced_compilation/hello_vulkan.h deleted file mode 100644 index 38a2d73..0000000 --- a/ray_tracing_advanced_compilation/hello_vulkan.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" -#include "nvvk/sbtwrapper_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ instances - nvvk::Buffer m_bufReference; // Buffer references of the OBJ - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - nvvk::SBTWrapper m_sbtWrapper; - // Push constant for ray tracer - VkPipeline m_rtShaderLibrary; - - - PushConstantRay m_pcRay{{}, {}, 0, 0, 7}; -}; diff --git a/ray_tracing_advanced_compilation/images/advanced_compilation.png b/ray_tracing_advanced_compilation/images/advanced_compilation.png deleted file mode 100644 index 8110cbc..0000000 Binary files a/ray_tracing_advanced_compilation/images/advanced_compilation.png and /dev/null differ diff --git a/ray_tracing_advanced_compilation/images/deferred_host_operations.png b/ray_tracing_advanced_compilation/images/deferred_host_operations.png deleted file mode 100644 index 74b60e4..0000000 Binary files a/ray_tracing_advanced_compilation/images/deferred_host_operations.png and /dev/null differ diff --git a/ray_tracing_advanced_compilation/images/high_level_advanced_compilation.png b/ray_tracing_advanced_compilation/images/high_level_advanced_compilation.png deleted file mode 100644 index 982afb4..0000000 Binary files a/ray_tracing_advanced_compilation/images/high_level_advanced_compilation.png and /dev/null differ diff --git a/ray_tracing_advanced_compilation/images/high_level_regular_compilation.png b/ray_tracing_advanced_compilation/images/high_level_regular_compilation.png deleted file mode 100644 index bcf3a3f..0000000 Binary files a/ray_tracing_advanced_compilation/images/high_level_regular_compilation.png and /dev/null differ diff --git a/ray_tracing_advanced_compilation/images/library.png b/ray_tracing_advanced_compilation/images/library.png deleted file mode 100644 index bc0e4ef..0000000 Binary files a/ray_tracing_advanced_compilation/images/library.png and /dev/null differ diff --git a/ray_tracing_advanced_compilation/images/regular_pipeline.png b/ray_tracing_advanced_compilation/images/regular_pipeline.png deleted file mode 100644 index cb8b126..0000000 Binary files a/ray_tracing_advanced_compilation/images/regular_pipeline.png and /dev/null differ diff --git a/ray_tracing_advanced_compilation/images/single_threaded_compilation.png b/ray_tracing_advanced_compilation/images/single_threaded_compilation.png deleted file mode 100644 index b01fc65..0000000 Binary files a/ray_tracing_advanced_compilation/images/single_threaded_compilation.png and /dev/null differ diff --git a/ray_tracing_advanced_compilation/main.cpp b/ray_tracing_advanced_compilation/main.cpp deleted file mode 100644 index b67aea1..0000000 --- a/ray_tracing_advanced_compilation/main.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } - - // Specialization - ImGui::SliderInt("Specialization", &helloVk.m_pcRay.specialization, 0, 7); - int s = helloVk.m_pcRay.specialization; - int a = ((s >> 2) % 2) == 1; - int b = ((s >> 1) % 2) == 1; - int c = ((s >> 0) % 2) == 1; - ImGui::Checkbox("Use Diffuse", (bool*)&a); - ImGui::Checkbox("Use Specular", (bool*)&b); - ImGui::Checkbox("Trace shadow", (bool*)&c); - helloVk.m_pcRay.specialization = (a << 2) + (b << 1) + c; -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_advanced_compilation/shaders/frag_shader.frag b/ray_tracing_advanced_compilation/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_advanced_compilation/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_advanced_compilation/shaders/host_device.h b/ray_tracing_advanced_compilation/shaders/host_device.h deleted file mode 100644 index 11265e8..0000000 --- a/ray_tracing_advanced_compilation/shaders/host_device.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; - int specialization; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_advanced_compilation/shaders/passthrough.vert b/ray_tracing_advanced_compilation/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_advanced_compilation/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_advanced_compilation/shaders/post.frag b/ray_tracing_advanced_compilation/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_advanced_compilation/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_advanced_compilation/shaders/raycommon.glsl b/ray_tracing_advanced_compilation/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing_advanced_compilation/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing_advanced_compilation/shaders/raytrace.rchit b/ray_tracing_advanced_compilation/shaders/raytrace.rchit deleted file mode 100644 index 66d634c..0000000 --- a/ray_tracing_advanced_compilation/shaders/raytrace.rchit +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; -layout(constant_id = 0) const int USE_DIFFUSE = 1; -layout(constant_id = 1) const int USE_SPECULAR = 1; -layout(constant_id = 2) const int TRACE_SHADOW = 1; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = vec3(0); - if(USE_DIFFUSE == 1) - { - diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - if(TRACE_SHADOW == 1) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - } - else - isShadowed = false; - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - if(USE_SPECULAR == 1) - { - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_advanced_compilation/shaders/raytrace.rgen b/ray_tracing_advanced_compilation/shaders/raytrace.rgen deleted file mode 100644 index c2ba199..0000000 --- a/ray_tracing_advanced_compilation/shaders/raytrace.rgen +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - pcRay.specialization, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0)); -} diff --git a/ray_tracing_advanced_compilation/shaders/raytrace.rmiss b/ray_tracing_advanced_compilation/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_advanced_compilation/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_advanced_compilation/shaders/raytraceShadow.rmiss b/ray_tracing_advanced_compilation/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_advanced_compilation/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_advanced_compilation/shaders/vert_shader.vert b/ray_tracing_advanced_compilation/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_advanced_compilation/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_advanced_compilation/shaders/wavefront.glsl b/ray_tracing_advanced_compilation/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_advanced_compilation/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_animation/CMakeLists.txt b/ray_tracing_animation/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_animation/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_animation/README.md b/ray_tracing_animation/README.md deleted file mode 100644 index 221dac2..0000000 --- a/ray_tracing_animation/README.md +++ /dev/null @@ -1,454 +0,0 @@ -# Ray Tracing Animation - Tutorial - -![](images/animation2.gif) - -## Tutorial ([Setup](../docs/setup.md)) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -We will implement two animation methods: only the transformation matrices, and animating the geometry itself. - -## Animating the Matrices - -This first example shows how we can update the matrices used for instances in the TLAS. - -### Creating a Scene - -In main.cpp we can create a new scene with a ground plane and 21 instances of the Wuson model, by replacing the -`helloVk.loadModel` calls in `main()`. The code below creates all of the instances -at the same position, but we will displace them later in the animation function. If you run the example, -you will find that the rendering is considerably slow, because the geometries are exactly at the same position -and the acceleration structure does not deal with this well. - -~~~~ C++ - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths), - glm::scale(glm::mat4(1.f),glm::vec3(2.f, 1.f, 2.f))); - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths)); - uint32_t wusonId = 1; - glm::mat4 identity{1}; - for(int i = 0; i < 20; i++) - helloVk.m_instances.push_back({identity, wusonId}); -~~~~ - -### Animation Function - -We want to have all of the Wuson models running in a circle, and we will first modify the rasterizer to handle this. -Animating the transformation matrices will be done entirely on the CPU, and we will copy the computed transformation to the GPU. -In the next example, the animation will be done on the GPU using a compute shader. - -Add the declaration of the animation to the `HelloVulkan` class. - -~~~~ C++ -void animationInstances(float time); -~~~~ - -The first part computes the transformations for all of the Wuson models, placing each one behind another. - -~~~~ C++ -void HelloVulkan::animationInstances(float time) -{ - const int32_t nbWuson = static_cast(m_instances.size() - 1); - const float deltaAngle = 6.28318530718f / static_cast(nbWuson); - const float wusonLength = 3.f; - const float radius = wusonLength / (2.f * sin(deltaAngle / 2.0f)); - const float offset = time * 0.5f; - - for(int i = 0; i < nbWuson; i++) - { - int wusonIdx = i + 1; - auto& transform = m_instances[wusonIdx].transform; - transform = glm::rotation_mat4_y(i * deltaAngle + offset) - * glm::translate(glm::mat4(1),radius, 0.f, 0.f); - } -~~~~ - -### Loop Animation - -In `main()`, just before the main loop, add a variable to hold the start time. -We will use this time in our animation function. - -~~~~ C++ - auto start = std::chrono::system_clock::now(); -~~~~ - -Inside the `while` loop, just before calling `appBase.prepareFrame()`, invoke the animation function. - -~~~~ C++ - std::chrono::duration diff = std::chrono::system_clock::now() - start; - helloVk.animationInstances(diff.count()); -~~~~ - -If you run the application, the Wuson models will be running in a circle when using the rasterizer, but -they will still be at their original positions in the ray traced version. We will need to update the TLAS for this. - -## Update TLAS - -Since we want to update the transformation matrices in the TLAS, we need to keep some of the objects used to create it. - -First, move the vector of `nvvk::RaytracingBuilder::Instance` objects from `HelloVulkan::createTopLevelAS()` to the -`HelloVulkan` class. - -~~~~ C++ -std::vector m_tlas; -~~~~ - -Make sure to rename it to `m_tlas`, instead of `tlas`. - -One important point is that we need to set the TLAS build flags to allow updates, by adding the`VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR` flag. -This is absolutely needed, since otherwise the TLAS cannot be updated. - -~~~~ C++ -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - m_tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - m_tlas.emplace_back(rayInst); - } - - m_rtFlags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; - m_rtBuilder.buildTlas(m_tlas, m_rtFlags); -} -~~~~ - -Back in `HelloVulkan::animationInstances()`, we need to update the TLAS by calling -`buildTlas` with the update to `true`. - -~~~~ C++ - m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true); -~~~~ - -![](images/animation1.gif) - -### nvvk::RaytracingBuilder::buildTlas (Implementation) - -We are using `nvvk::RaytracingBuilder` to update the matrices for convenience. There -is only a small variation with constructing the matrices and updating them. The main -differences are: - -* 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. - -What is happening is the buffer containing all matrices will be updated and the `vkCmdBuildAccelerationStructuresKHR` will update the acceleration in place. - -## BLAS Animation - -In the previous chapter, we updated the transformation matrices. In this one we will modify vertices in a compute shader. - -### Adding a Sphere - -In this chapter, we will animate a sphere. In `main.cpp`, set up the scene like this: - -~~~~ C++ - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), - glm::scale(glm::mat4(1.f),glm::vec3(2.f, 1.f, 2.f))); - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true)); - uint32_t wusonId = 1; - glm::mat4 identity{1}; - for(int i = 0; i < 5; i++) - { - helloVk.m_instances.push_back({identity, wusonId}); - } - helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true)); -~~~~ - -Because we now have a new instance, we have to adjust the calculation of the number of Wuson models in `HelloVulkan::animationInstances()`. - -~~~~ C++ - const int32_t nbWuson = static_cast(m_instances.size() - 2); // All except sphere and plane -~~~~ - -### Compute Shader - -The compute shader will update the vertices in-place. - -Add all of the following members to the `HelloVulkan` class: - -~~~~ C++ - void createCompDescriptors(); - void updateCompDescriptors(nvvkBuffer& vertex); - void createCompPipelines(); - - nvvk::DescriptorSetBindings m_compDescSetLayoutBind; - VkDescriptorPool m_compDescPool; - VkDescriptorSetLayout m_compDescSetLayout; - VkDescriptorSet m_compDescSet; - VkPipeline m_compPipeline; - VkPipelineLayout m_compPipelineLayout; -~~~~ - -The compute shader will work on a single `VertexObj` buffer. - -~~~~ C++ -void HelloVulkan::createCompDescriptors() -{ - m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); - - m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); - m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); - m_compDescSet = nvvk::allocateDescriptorSet(m_device, m_compDescPool, m_compDescSetLayout); -} -~~~~ - -`updateCompDescriptors` will set the set the descriptor to the buffer of `VertexObj` objects to which the animation will be applied. - -~~~~ C++ -void HelloVulkan::updateCompDescriptors(nvvk::Buffer& vertex) -{ - std::vector writes; - VkDescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &dbiUnif)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} -~~~~ - -The compute pipeline will consist of a simple shader and a push constant, which will be used -to set the animation time. - -~~~~ C++ -void HelloVulkan::createCompPipelines() -{ - // pushing time - VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float)}; - - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_compDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &push_constants; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_compPipelineLayout); - - - VkComputePipelineCreateInfo computePipelineCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; - computePipelineCreateInfo.layout = m_compPipelineLayout; - - computePipelineCreateInfo.stage = - nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/anim.comp.spv", true, defaultSearchPaths, true), - VK_SHADER_STAGE_COMPUTE_BIT); - - vkCreateComputePipelines(m_device, {}, 1, &computePipelineCreateInfo, nullptr, &m_compPipeline); - - vkDestroyShaderModule(m_device, computePipelineCreateInfo.stage.module, nullptr); -} -~~~~ - -Finally, destroy the resources in `HelloVulkan::destroyResources()`: - -~~~~ C++ - // #VK_compute - vkDestroyPipeline(m_device, m_compPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr); -~~~~ - -### `anim.comp` - -The compute shader will be simple. We need to add a new shader file, `anim.comp`, to the `shaders` filter in the solution. - -This will move each vertex up and down over time. - -~~~~ C++ -#version 460 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#include "wavefront.glsl" - -layout(binding = 0, scalar) buffer Vertices -{ - Vertex v[]; -} -vertices; - -layout(push_constant) uniform shaderInformation -{ - float iTime; -} -pushc; - -void main() -{ - Vertex v0 = vertices.v[gl_GlobalInvocationID.x]; - - // Compute vertex position - const float PI = 3.14159265; - const float signY = (v0.pos.y >= 0 ? 1 : -1); - const float radius = length(v0.pos.xz); - const float argument = pushc.iTime * 4 + radius * PI; - const float s = sin(argument); - v0.pos.y = signY * abs(s) * 0.5; - - // Compute normal - if(radius == 0.0f) - { - v0.nrm = vec3(0.0f, signY, 0.0f); - } - else - { - const float c = cos(argument); - const float xzFactor = -PI * s * c; - const float yFactor = 2.0f * signY * radius * abs(s); - v0.nrm = normalize(vec3(v0.pos.x * xzFactor, yFactor, v0.pos.z * xzFactor)); - } - - vertices.v[gl_GlobalInvocationID.x] = v0; -} -~~~~ - -### Animating the Object - -First add the declaration of the animation function in `HelloVulkan`: - -~~~~ C++ -void animationObject(float time); -~~~~ - -The implementation only pushes the current time and calls the compute shader (`dispatch`). - -~~~~ C++ -void HelloVulkan::animationObject(float time) -{ - const uint32_t sphereId = 2; - ObjModel& model = m_objModel[sphereId]; - - updateCompDescriptors(model.vertexBuffer); - - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); - - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr); - vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float), &time); - vkCmdDispatch(cmdBuf, model.nbVertices, 1, 1); - - genCmdBuf.submitAndWait(cmdBuf); -} -~~~~ - -### Invoking Animation - -In `main.cpp`, after the other resource creation functions, add the creation functions for the compute shader. - -~~~~ C++ - helloVk.createCompDescriptors(); - helloVk.createCompPipelines(); -~~~~ - -In the rendering loop, **before** the call to `animationInstances`, call the object animation function. - -~~~~ C++ - helloVk.animationObject(diff.count()); -~~~~ - -**:warning: Note:** Always update the TLAS when BLAS are modified. This will make sure that the TLAS knows about the new bounding box sizes. - -**:warning: 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 - -In `nvvk::RaytracingBuilder` in `raytrace_vkpp.hpp`, we can add a function to update a BLAS whose vertex buffer was previously updated. This function is very similar to the one used for instances, but in this case, there is no buffer transfer to do. - -~~~~ C++ -//-------------------------------------------------------------------------------------------------- -// Refit BLAS number blasIdx from updated buffer contents. -// -void nvvk::RaytracingBuilderKHR::updateBlas(uint32_t blasIdx, BlasInput& blas, VkBuildAccelerationStructureFlagsKHR flags) -{ - assert(size_t(blasIdx) < m_blas.size()); - - // Preparing all build information, acceleration is filled later - VkAccelerationStructureBuildGeometryInfoKHR buildInfos{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR}; - buildInfos.flags = flags; - buildInfos.geometryCount = (uint32_t)blas.asGeometry.size(); - buildInfos.pGeometries = blas.asGeometry.data(); - buildInfos.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR; // UPDATE - buildInfos.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - buildInfos.srcAccelerationStructure = m_blas[blasIdx].accel; // UPDATE - buildInfos.dstAccelerationStructure = m_blas[blasIdx].accel; - - // Find size to build on the device - std::vector maxPrimCount(blas.asBuildOffsetInfo.size()); - for(auto tt = 0; tt < blas.asBuildOffsetInfo.size(); tt++) - maxPrimCount[tt] = blas.asBuildOffsetInfo[tt].primitiveCount; // Number of primitives/triangles - VkAccelerationStructureBuildSizesInfoKHR sizeInfo{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR}; - vkGetAccelerationStructureBuildSizesKHR(m_device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfos, - maxPrimCount.data(), &sizeInfo); - - // Allocate the scratch buffer and setting the scratch info - nvvk::Buffer scratchBuffer = - m_alloc->createBuffer(sizeInfo.buildScratchSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); - VkBufferDeviceAddressInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO}; - bufferInfo.buffer = scratchBuffer.buffer; - buildInfos.scratchData.deviceAddress = vkGetBufferDeviceAddress(m_device, &bufferInfo); - NAME_VK(scratchBuffer.buffer); - - std::vector pBuildOffset(blas.asBuildOffsetInfo.size()); - for(size_t i = 0; i < blas.asBuildOffsetInfo.size(); i++) - pBuildOffset[i] = &blas.asBuildOffsetInfo[i]; - - // Update the instance buffer on the device side and build the TLAS - nvvk::CommandPool genCmdBuf(m_device, m_queueIndex); - VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); - - - // Update the acceleration structure. Note the VK_TRUE parameter to trigger the update, - // and the existing BLAS being passed and updated in place - vkCmdBuildAccelerationStructuresKHR(cmdBuf, 1, &buildInfos, pBuildOffset.data()); - - genCmdBuf.submitAndWait(cmdBuf); - m_alloc->destroy(scratchBuffer); -} -~~~~ - -The previous function (`updateBlas`) uses geometry information stored in `m_blas`. -To be able to re-use this information, we need to keep the structure of `nvvk::RaytracingBuilderKHR::Blas` objects -used for its creation. - -Move the `nvvk::RaytracingBuilderKHR::Blas` vector from `HelloVulkan::createBottomLevelAS()` to the `HelloVulkan` class, renaming it to `m_blas`. - -~~~~ C++ - std::vector m_blas; -~~~~ - -As with the TLAS, the BLAS needs to allow updates. We will also enable the -`VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR` flag, which indicates that the given -acceleration structure build should prioritize build time over trace performance. - -~~~~ C++ -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - m_blas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - m_blas.push_back(blas); - } - m_rtBuilder.buildBlas(m_blas, VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR - | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); -} -~~~~ - -Finally, we can add a line at the end of `HelloVulkan::animationObject()` to update the BLAS. - -~~~~ C++ -m_rtBuilder.updateBlas(sphereId, m_blas[sphereId], - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); -~~~~ - -![](images/animation2.gif) diff --git a/ray_tracing_animation/hello_vulkan.cpp b/ray_tracing_animation/hello_vulkan.cpp deleted file mode 100644 index 14f84be..0000000 --- a/ray_tracing_animation/hello_vulkan.cpp +++ /dev/null @@ -1,966 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - m_sbtWrapper.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - - - // #VK_compute - vkDestroyPipeline(m_device, m_compPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); - m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - m_blas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - m_blas.push_back(blas); - } - m_rtBuilder.buildBlas(m_blas, VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR - | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - m_tlas.emplace_back(rayInst); - } - - m_rtFlags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; - m_rtBuilder.buildTlas(m_tlas, m_rtFlags); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - - m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - auto& regions = m_sbtWrapper.getRegions(); - vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -// #VK_animation - -//-------------------------------------------------------------------------------------------------- -// Making the Wuson running in circle -// -void HelloVulkan::animationInstances(float time) -{ - const auto nbWuson = static_cast(m_instances.size() - 2); // All except sphere and plane - const float deltaAngle = 6.28318530718f / static_cast(nbWuson); - const float wusonLength = 3.f; - const float radius = wusonLength / (2.f * sin(deltaAngle / 2.0f)); - const float offset = time * 0.5f; - - for(int i = 0; i < nbWuson; i++) - { - int wusonIdx = i + 1; - glm::mat4 transform = m_instances[wusonIdx].transform; - transform = glm::rotate(transform, i * deltaAngle + offset, glm::vec3(0.f, 1.f, 0.f)); - transform = glm::translate(transform, glm::vec3(radius, 0.f, 0.f)); - - VkAccelerationStructureInstanceKHR& tinst = m_tlas[wusonIdx]; - tinst.transform = nvvk::toTransformMatrixKHR(transform); - } - - // Updating the top level acceleration structure - m_rtBuilder.buildTlas(m_tlas, m_rtFlags, true); -} - -//-------------------------------------------------------------------------------------------------- -// Animating the sphere vertices using a compute shader -// -void HelloVulkan::animationObject(float time) -{ - const uint32_t sphereId = 2; - ObjModel& model = m_objModel[sphereId]; - - updateCompDescriptors(model.vertexBuffer); - - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); - - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr); - vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float), &time); - vkCmdDispatch(cmdBuf, model.nbVertices, 1, 1); - - genCmdBuf.submitAndWait(cmdBuf); - m_rtBuilder.updateBlas(sphereId, m_blas[sphereId], - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR); -} - -////////////////////////////////////////////////////////////////////////// -// #VK_compute -void HelloVulkan::createCompDescriptors() -{ - m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); - - m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); - m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); - m_compDescSet = nvvk::allocateDescriptorSet(m_device, m_compDescPool, m_compDescSetLayout); -} - -void HelloVulkan::updateCompDescriptors(nvvk::Buffer& vertex) -{ - std::vector writes; - VkDescriptorBufferInfo dbiUnif{vertex.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &dbiUnif)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - -void HelloVulkan::createCompPipelines() -{ - // pushing time - VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(float)}; - - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_compDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &push_constants; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_compPipelineLayout); - - - VkComputePipelineCreateInfo computePipelineCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; - computePipelineCreateInfo.layout = m_compPipelineLayout; - - computePipelineCreateInfo.stage = - nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/anim.comp.spv", true, defaultSearchPaths, true), - VK_SHADER_STAGE_COMPUTE_BIT); - - vkCreateComputePipelines(m_device, {}, 1, &computePipelineCreateInfo, nullptr, &m_compPipeline); - - vkDestroyShaderModule(m_device, computePipelineCreateInfo.stage.module, nullptr); -} diff --git a/ray_tracing_animation/hello_vulkan.h b/ray_tracing_animation/hello_vulkan.h deleted file mode 100644 index 00e8e7c..0000000 --- a/ray_tracing_animation/hello_vulkan.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" -#include "nvvk/sbtwrapper_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - nvvk::SBTWrapper m_sbtWrapper; - - std::vector m_tlas; - std::vector m_blas; - - // Push constant for ray tracer - PushConstantRay m_pcRay{}; - - // #VK_animation - void animationInstances(float time); - void animationObject(float time); - - // #VK_compute - void createCompDescriptors(); - void updateCompDescriptors(nvvk::Buffer& vertex); - void createCompPipelines(); - - nvvk::DescriptorSetBindings m_compDescSetLayoutBind; - VkDescriptorPool m_compDescPool; - VkDescriptorSetLayout m_compDescSetLayout; - VkDescriptorSet m_compDescSet; - VkPipeline m_compPipeline; - VkPipelineLayout m_compPipelineLayout; - - VkBuildAccelerationStructureFlagsKHR m_rtFlags; -}; diff --git a/ray_tracing_animation/images/animation1.gif b/ray_tracing_animation/images/animation1.gif deleted file mode 100644 index e2fd7ee..0000000 Binary files a/ray_tracing_animation/images/animation1.gif and /dev/null differ diff --git a/ray_tracing_animation/images/animation2.gif b/ray_tracing_animation/images/animation2.gif deleted file mode 100644 index 85dee40..0000000 Binary files a/ray_tracing_animation/images/animation2.gif and /dev/null differ diff --git a/ray_tracing_animation/main.cpp b/ray_tracing_animation/main.cpp deleted file mode 100644 index f5a550e..0000000 --- a/ray_tracing_animation/main.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), - glm::scale(glm::mat4(1.f), glm::vec3(2.f, 1.f, 2.f))); - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true)); - uint32_t wusonId = 1; - glm::mat4 identity{1}; - for(int i = 0; i < 5; i++) - { - helloVk.m_instances.push_back({identity, wusonId}); - } - helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true)); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - // #VK_compute - helloVk.createCompDescriptors(); - helloVk.createCompPipelines(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - auto start = std::chrono::system_clock::now(); - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // #VK_animation - std::chrono::duration diff = std::chrono::system_clock::now() - start; - helloVk.animationObject(diff.count()); - helloVk.animationInstances(diff.count()); - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_animation/shaders/anim.comp b/ray_tracing_animation/shaders/anim.comp deleted file mode 100644 index 72b5bde..0000000 --- a/ray_tracing_animation/shaders/anim.comp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#include "wavefront.glsl" - -layout(binding = 0, scalar) buffer Vertices_ -{ - Vertex v[]; -} -vertices; - -layout(push_constant) uniform shaderInformation -{ - float iTime; -} -pushc; - -void main() -{ - Vertex v0 = vertices.v[gl_GlobalInvocationID.x]; - - // Compute vertex position - const float PI = 3.14159265; - const float signY = (v0.pos.y >= 0 ? 1 : -1); - const float radius = length(v0.pos.xz); - const float argument = pushc.iTime * 4 + radius * PI; - const float s = sin(argument); - v0.pos.y = signY * abs(s) * 0.5; - - // Compute normal - if(radius == 0.0f) - { - v0.nrm = vec3(0.0f, signY, 0.0f); - } - else - { - const float c = cos(argument); - const float xzFactor = -PI * s * c; - const float yFactor = 2.0f * signY * radius * abs(s); - v0.nrm = normalize(vec3(v0.pos.x * xzFactor, yFactor, v0.pos.z * xzFactor)); - } - - vertices.v[gl_GlobalInvocationID.x] = v0; -} \ No newline at end of file diff --git a/ray_tracing_animation/shaders/frag_shader.frag b/ray_tracing_animation/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_animation/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_animation/shaders/host_device.h b/ray_tracing_animation/shaders/host_device.h deleted file mode 100644 index a22192e..0000000 --- a/ray_tracing_animation/shaders/host_device.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_animation/shaders/passthrough.vert b/ray_tracing_animation/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_animation/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_animation/shaders/post.frag b/ray_tracing_animation/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_animation/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_animation/shaders/raycommon.glsl b/ray_tracing_animation/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing_animation/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing_animation/shaders/raytrace.rchit b/ray_tracing_animation/shaders/raytrace.rchit deleted file mode 100644 index 2eb634e..0000000 --- a/ray_tracing_animation/shaders/raytrace.rchit +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_animation/shaders/raytrace.rgen b/ray_tracing_animation/shaders/raytrace.rgen deleted file mode 100644 index 4802cd0..0000000 --- a/ray_tracing_animation/shaders/raytrace.rgen +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0)); -} diff --git a/ray_tracing_animation/shaders/raytrace.rmiss b/ray_tracing_animation/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_animation/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_animation/shaders/raytraceShadow.rmiss b/ray_tracing_animation/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_animation/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_animation/shaders/vert_shader.vert b/ray_tracing_animation/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_animation/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_animation/shaders/wavefront.glsl b/ray_tracing_animation/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_animation/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_anyhit/CMakeLists.txt b/ray_tracing_anyhit/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_anyhit/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_anyhit/README.md b/ray_tracing_anyhit/README.md deleted file mode 100644 index e75b330..0000000 --- a/ray_tracing_anyhit/README.md +++ /dev/null @@ -1,397 +0,0 @@ -# Any Hit Shaders - Tutorial -Authors: [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/), Neil Bickford - -![](../docs/Images/anyhit.png) - - -## Tutorial ([Setup](../docs/setup.md)) - - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -Like closest hit shaders, any hit shaders operate on intersections between rays and geometry. However, the any hit -shader will be executed for all hits along the ray. The closest hit shader will then be invoked on the closest accepted -intersection. - -The any hit shader can be useful for discarding intersections, such as for alpha cutouts for example, but can also be -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. - - **Note:** - This example is based on many elements from the [Antialiasing Tutorial](../ray_tracing_jitter_cam/README.md). - - - -## Any Hit Shader - -Create a new shader file `raytrace.rahit` and rerun CMake to have it added to the solution. - -This shader starts like `raytrace.chit`, but uses less information. -~~~~ C++ -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "random.glsl" -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -// clang-format on -~~~~ - - **:warning: Note:** - You can find the source of `random.glsl` in the Antialiasing Tutorial [here](../ray_tracing_jitter_cam/README.md#toc1.1). - - -For the any hit shader, we need to know which material we hit, and whether that material supports transparency. If it is -opaque, we simply return, which means that the hit will be accepted. - -~~~~ C++ -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - if (mat.illum != 4) - return; -~~~~ - -Now we will apply transparency: - -~~~~ C++ - if (mat.dissolve == 0.0) - ignoreIntersectionEXT(); - else if(rnd(prd.seed) > mat.dissolve) - ignoreIntersectionEXT(); -} -~~~~ - -As you can see, we are using a random number generator to determine if the ray hits or ignores the object. If we -accumulate enough rays, the final result will converge to what we want. - -## Payload - -The random `seed` also needs to be passed in the ray payload. - -In `raycommon.glsl`, add the seed: - -~~~~ C++ -struct hitPayload -{ - vec3 hitValue; - uint seed; -}; -~~~~ - -## Adding Any Hit to RT Pipeline - -The any hit shader will be part of the hit shader group. Currently, the hit shader group only contains the closest hit shader. - -In `createRtPipeline()`, after loading `raytrace.rchit.spv`, load `raytrace.rahit.spv` - -~~~~ C++ - enum StageIndices - { - ... - eAnyHit, - eShaderGroupCount - }; - - // Hit Group - Any Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - stages[eAnyHit] = stage; -~~~~ - -The Any Hit goes in the same Hit group as the Closest Hit, so we need to -add the Any Hit stage index and push back the shader module to the stages. - -~~~~ C++ - // closest hit shader - // Payload 0 - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - group.anyHitShader = eAnyHit; - m_rtShaderGroups.push_back(group); -~~~~ - -## Give access of the buffers to the Any Hit shader - -In `createDescriptorSetLayout()`, we need to allow the Any Hit shader to access the scene description buffer - -~~~~ C++ - // Obj descriptions - m_descSetLayoutBind.addBinding(eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT - | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); -~~~~ - -## Opaque Flag - -In the example, when creating `VkAccelerationStructureGeometryKHR` objects, we set their flags to `VK_GEOMETRY_OPAQUE_BIT_KHR`. However, this avoided invoking the any hit shader. - -We could remove all of the flags, but another issue could happen: the any hit shader could be called multiple times for the same triangle. To have the any hit shader process only one hit per triangle, set the `VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR` flag: - -~~~~ C++ -asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // Avoid double hits; -~~~~ - -## Ray Generation Shader - -If you have done the previous [Jitter Camera/Antialiasing](../ray_tracing_jitter_cam) tutorial, -you will need just a few changes. - -First, `seed` will need to be available in the any hit shader, which is the reason we have added it to the hitPayload structure. - -Change the local `seed` to `prd.seed` everywhere. - -~~~~ C++ -prd.seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pushC.frame); -~~~~ - -For optimization, the `TraceRayEXT` call was using the `gl_RayFlagsOpaqueEXT` flag. But -this will skip the any hit shader, so change it to - -~~~~ C++ -uint rayFlags = gl_RayFlagsNoneEXT; -~~~~ - -## Closest Hit Shader - -Similarly, in the closest hit shader, change the flag to `gl_RayFlagsSkipClosestHitShaderEXT`, as we want to enable the any hit and miss shaders, but we still don't care -about the closest hit shader for shadow rays. This will enable transparent shadows. - -~~~~ C++ -uint flags = gl_RayFlagsSkipClosestHitShaderEXT; -~~~~ - -## Scene and Model - -For a more interesting scene, you can replace the `helloVk.loadModel` calls in `main()` with the following scene: - -~~~~ C++ - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true), - glm::scale(glm::mat4(1.f),glm::vec3(1.5f)) - * glm::translate(glm::mat4(1),glm::vec3(0.0f, 1.0f, 0.0f))); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); -~~~~ - -## OBJ Materials - -By default, all objects are opaque, you will need to change the material description. - -Edit the first few lines of `media/scenes/wuson.mtl` and `media/scenes/sphere.mtl` to use a new illumination model (4) with a dissolve value of 0.5: - -~~~~ C++ -newmtl default -illum 4 -d 0.5 -... -~~~~ - -## Accumulation - -As mentioned earlier, for the effect to work, we need to accumulate frames over time. Please implement the following from [Jitter Camera/Antialiasing](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/tree/master/ray_tracing_jitter_cam): - -* [Frame Number](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/tree/master/ray_tracing_jitter_cam#frame-number) -* [Storing or Updating](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/tree/master/ray_tracing_jitter_cam#storing-or-updating) -* [Application Frame Update](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/tree/master/ray_tracing_jitter_cam#application-frame-update) - - -## Fixing The Pipeline - -The above code works, but might not work in the future. The reason is, the shadow ray `traceRayEXT` call in the Closest Hit shader, uses payload 1 -and when intersecting the object, the any hit shader will be executed using payload 0. In the time of writing those lines, the driver add -padding and there are no side effect, but this is not how thing should be done. - -Each `traceRayEXT` invocation should have as many Hit Groups as there are trace calls with different payload. For the other examples, it is still fine, -because we are using the `gl_RayFlagsSkipClosestHitShaderNV` flag and the closest hit shader (payload 0) will not be called and there were not -any hit or intersection shaders in the Hit Group. But in this example, the closest hit will be skiped, but not the any hit. - -**To fix this**, we need to add another hit group. - -This is how the current SBT looks like. - -![](images/anyhit_0.png) - -And we need to add the following to the ray tracing pipeline, a copy of the previous Hit Group, with a new AnyHit using the proper payload. - -![](images/anyhit_01.png) - - -### New shaders - -Create two new files `raytrace_0.ahit` and `raytrace_1.ahit`, and rename `raytrace.ahit` to `raytrace_ahit.glsl` - - **Note:** - Cmake need to be re-run to add the new files to the project. - -In `raytrace_0.ahit` add the following code - -~~~~ C -#version 460 -#extension GL_GOOGLE_include_directive : enable - -#define PAYLOAD_0 -#include "raytrace_rahit.glsl" -~~~~ - -and in `raytrace_1.ahit`, replace `PAYLOAD_0` by `PAYLOAD_1` - -Then in `raytrace_ahit.glsl` remove the `#version 460` and add the following code, so that we have the right layout. - -~~~~ C -#ifdef PAYLOAD_0 -layout(location = 0) rayPayloadInNV hitPayload prd; -#elif defined(PAYLOAD_1) -layout(location = 1) rayPayloadInNV shadowPayload prd; -#endif -~~~~ - -### New Payload - -We cannot simply have a bool for our shadow ray payload. We also need the `seed` for the random function. - -In the `raycommon.glsl` file, add the following structure - -~~~~ C -struct shadowPayload -{ - bool isHit; - uint seed; -}; -~~~~ - -The usage of the shadow payload is done in the closest hit and shadow miss shader. First, let's modify `raytraceShadow.rmiss` to look like this - -~~~~ C -#version 460 -#extension GL_NV_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable - -#include "raycommon.glsl" - -layout(location = 1) rayPayloadInNV shadowPayload prd; - -void main() -{ - prd.isHit = false; -} -~~~~ - -The the change in the closest hit shader `raytrace.rchit`, need to change the usage of the payload, but also the call to `traceRayEXT` - -Replace the payload to - -~~~~ C -layout(location = 1) rayPayloadNV shadowPayload prdShadow; -~~~~ - -Then just before the call to `traceRayEXT`, initialize the values to - -~~~~ C -prdShadow.isHit = true; -prdShadow.seed = prd.seed; -~~~~ - -and after the trace, set the seed value back to the main payload - -~~~~ C -prd.seed = prdShadow.seed; -~~~~ - -And check if the trace shadow hit an object of not - -~~~~ C -if(prdShadow.isHit) -~~~~ - -### traceRayEXT - -When we call `traceRayEXT`, since we are using the payload 1 (last argument), we also -need the trace to hit the alternative hit group, the one using the payload 1. -To do this, we need to set the sbtRecordOffset to 1 - -~~~~ C -traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 1, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); -~~~~ - - -### Ray tracing Pipeline - -The final step is to add the new Hit Group. This is a change in `HelloVulkan::createRtPipeline()`. -We need to load the new any hit shader and create a new Hit Group. - -Replace the `"shaders/raytrace.rahit.spv"` for `"shaders/raytrace_0.rahit.spv"` - -Load the new shader module. - -~~~~ C - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eAnyHit, - eAnyHit2, - eShaderGroupCount - }; - - // Hit Group - Any Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_0.rahit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - stages[eAnyHit] = stage; - // - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_1.rahit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - stages[eAnyHit2] = stage; -~~~~ - -Then, after the creating of the first Hit Group, create a new one, where only the any hit using payload 1 -is added. We are skipping the closest hit shader in the trace call, so we can ignore it in the Hit Group. - -~~~~ C - // Payload 1 - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.anyHitShader = eAnyHit2; - m_rtShaderGroups.push_back(group); -~~~~ - - - **:warning: Note:** Re-Run - Everything should work as before, but now it does it right. - - diff --git a/ray_tracing_anyhit/hello_vulkan.cpp b/ray_tracing_anyhit/hello_vulkan.cpp deleted file mode 100644 index 9be019d..0000000 --- a/ray_tracing_anyhit/hello_vulkan.cpp +++ /dev/null @@ -1,981 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT - | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - m_alloc.destroy(m_rtSBTBuffer); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); - resetFrame(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // Avoid double hits; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eAnyHit, - eAnyHit2, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - // Hit Group - Any Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_0.rahit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - stages[eAnyHit] = stage; - // - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace_1.rahit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - stages[eAnyHit2] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - // Payload 0 - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - group.anyHitShader = eAnyHit; - m_rtShaderGroups.push_back(group); - - // Payload 1 - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.anyHitShader = eAnyHit2; - m_rtShaderGroups.push_back(group); - - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// The Shader Binding Table (SBT) -// - getting all shader handles and write them in a SBT buffer -// - Besides exception, this could be always done like this -// -void HelloVulkan::createRtShaderBindingTable() -{ - uint32_t missCount{2}; - uint32_t hitCount{2}; - auto handleCount = 1 + missCount + hitCount; - uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - - // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. - uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); - - m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member - m_missRegion.stride = handleSizeAligned; - m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_hitRegion.stride = handleSizeAligned; - m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - - // Get the shader group handles - uint32_t dataSize = handleCount * handleSize; - std::vector handles(dataSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); - assert(result == VK_SUCCESS); - - // Allocate a buffer for storing the SBT. - VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. - - // Find the SBT addresses of each group - VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; - VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - m_rgenRegion.deviceAddress = sbtAddress; - m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; - m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; - - // Helper to retrieve the handle data - auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; - - // Map the SBT buffer and write in the handles. - auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); - uint8_t* pData{nullptr}; - uint32_t handleIdx{0}; - // Raygen - pData = pSBTBuffer; - memcpy(pData, getHandle(handleIdx++), handleSize); - // Miss - pData = pSBTBuffer + m_rgenRegion.size; - for(uint32_t c = 0; c < missCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_missRegion.stride; - } - // Hit - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; - for(uint32_t c = 0; c < hitCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_hitRegion.stride; - } - - m_alloc.unmap(m_rtSBTBuffer); - m_alloc.finalizeAndReleaseStaging(); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - updateFrame(); - if(m_pcRay.frame >= m_maxFrames) - return; - - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); - - - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// If the camera matrix has changed, resets the frame. -// otherwise, increments frame. -// -void HelloVulkan::updateFrame() -{ - static glm::mat4 refCamMatrix; - static float refFov{CameraManip.getFov()}; - - const auto& m = CameraManip.getMatrix(); - const auto fov = CameraManip.getFov(); - - if(refCamMatrix != m || refFov != fov) - { - resetFrame(); - refCamMatrix = m; - refFov = fov; - } - m_pcRay.frame++; -} - -void HelloVulkan::resetFrame() -{ - m_pcRay.frame = -1; -} diff --git a/ray_tracing_anyhit/hello_vulkan.h b/ray_tracing_anyhit/hello_vulkan.h deleted file mode 100644 index 5e86089..0000000 --- a/ray_tracing_anyhit/hello_vulkan.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - void resetFrame(); - void updateFrame(); - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - - nvvk::Buffer m_rtSBTBuffer; - VkStridedDeviceAddressRegionKHR m_rgenRegion{}; - VkStridedDeviceAddressRegionKHR m_missRegion{}; - VkStridedDeviceAddressRegionKHR m_hitRegion{}; - VkStridedDeviceAddressRegionKHR m_callRegion{}; - - int m_maxFrames{10000}; - - // Push constant for ray tracer - PushConstantRay m_pcRay{}; -}; diff --git a/ray_tracing_anyhit/images/anyhit.png b/ray_tracing_anyhit/images/anyhit.png deleted file mode 100644 index 17cfb9d..0000000 Binary files a/ray_tracing_anyhit/images/anyhit.png and /dev/null differ diff --git a/ray_tracing_anyhit/images/anyhit_0.png b/ray_tracing_anyhit/images/anyhit_0.png deleted file mode 100644 index 552faa8..0000000 Binary files a/ray_tracing_anyhit/images/anyhit_0.png and /dev/null differ diff --git a/ray_tracing_anyhit/images/anyhit_01.png b/ray_tracing_anyhit/images/anyhit_01.png deleted file mode 100644 index 4ed780a..0000000 Binary files a/ray_tracing_anyhit/images/anyhit_01.png and /dev/null differ diff --git a/ray_tracing_anyhit/main.cpp b/ray_tracing_anyhit/main.cpp deleted file mode 100644 index 10f37fb..0000000 --- a/ray_tracing_anyhit/main.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/sphere.obj", defaultSearchPaths, true), - glm::scale(glm::mat4(1.f), glm::vec3(1.5f)) * glm::translate(glm::mat4(1.f), glm::vec3(0.0f, 1.0f, 0.0f))); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - helloVk.createRtShaderBindingTable(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_anyhit/shaders/frag_shader.frag b/ray_tracing_anyhit/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_anyhit/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_anyhit/shaders/host_device.h b/ray_tracing_anyhit/shaders/host_device.h deleted file mode 100644 index bf0ed9e..0000000 --- a/ray_tracing_anyhit/shaders/host_device.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; - int frame; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_anyhit/shaders/passthrough.vert b/ray_tracing_anyhit/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_anyhit/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_anyhit/shaders/post.frag b/ray_tracing_anyhit/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_anyhit/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_anyhit/shaders/random.glsl b/ray_tracing_anyhit/shaders/random.glsl deleted file mode 100644 index ef41f54..0000000 --- a/ray_tracing_anyhit/shaders/random.glsl +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -// Generate a random unsigned int from two unsigned int values, using 16 pairs -// of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis, -// "GPU Random Numbers via the Tiny Encryption Algorithm" -uint tea(uint val0, uint val1) -{ - uint v0 = val0; - uint v1 = val1; - uint s0 = 0; - - for(uint n = 0; n < 16; n++) - { - s0 += 0x9e3779b9; - v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); - v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); - } - - return v0; -} - -// Generate a random unsigned int in [0, 2^24) given the previous RNG state -// using the Numerical Recipes linear congruential generator -uint lcg(inout uint prev) -{ - uint LCG_A = 1664525u; - uint LCG_C = 1013904223u; - prev = (LCG_A * prev + LCG_C); - return prev & 0x00FFFFFF; -} - -// Generate a random float in [0, 1) given the previous RNG state -float rnd(inout uint prev) -{ - return (float(lcg(prev)) / float(0x01000000)); -} diff --git a/ray_tracing_anyhit/shaders/raycommon.glsl b/ray_tracing_anyhit/shaders/raycommon.glsl deleted file mode 100644 index 5260728..0000000 --- a/ray_tracing_anyhit/shaders/raycommon.glsl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; - uint seed; -}; - -struct shadowPayload -{ - bool isHit; - uint seed; -}; diff --git a/ray_tracing_anyhit/shaders/raytrace.rahit b/ray_tracing_anyhit/shaders/raytrace.rahit deleted file mode 100644 index 2831c6a..0000000 --- a/ray_tracing_anyhit/shaders/raytrace.rahit +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "random.glsl" -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -// clang-format on - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - if(mat.illum != 4) - return; - - if(mat.dissolve == 0.0) - ignoreIntersectionEXT; - else if(rnd(prd.seed) > mat.dissolve) - ignoreIntersectionEXT; -} diff --git a/ray_tracing_anyhit/shaders/raytrace.rchit b/ray_tracing_anyhit/shaders/raytrace.rchit deleted file mode 100644 index 08a273e..0000000 --- a/ray_tracing_anyhit/shaders/raytrace.rchit +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT shadowPayload prdShadow; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsSkipClosestHitShaderEXT; - prdShadow.isHit = true; - prdShadow.seed = prd.seed; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 1, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - prd.seed = prdShadow.seed; - - if(prdShadow.isHit) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_anyhit/shaders/raytrace.rgen b/ray_tracing_anyhit/shaders/raytrace.rgen deleted file mode 100644 index 8f2578f..0000000 --- a/ray_tracing_anyhit/shaders/raytrace.rgen +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#include "random.glsl" -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - -const int NBSAMPLES = 10; - -void main() -{ - // Initialize the random number - uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame); - - vec3 hitValues = vec3(0); - - for(int smpl = 0; smpl < NBSAMPLES; smpl++) - { - float r1 = rnd(seed); - float r2 = rnd(seed); - - // Subpixel jitter: send the ray through a different position inside the pixel - // each time, to provide antialiasing. - vec2 subpixel_jitter = pcRay.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2); - - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter; - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsNoneEXT; - float tMin = 0.001; - float tMax = 10000.0; - - prd.seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame); - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - hitValues += prd.hitValue; - } - prd.hitValue = hitValues / NBSAMPLES; - - // Do accumulation over time - if(pcRay.frame > 0) - { - float a = 1.0f / float(pcRay.frame + 1); - vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz; - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f)); - } - else - { - // First frame, replace the value in the buffer - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.f)); - } -} diff --git a/ray_tracing_anyhit/shaders/raytrace.rmiss b/ray_tracing_anyhit/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_anyhit/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_anyhit/shaders/raytraceShadow.rmiss b/ray_tracing_anyhit/shaders/raytraceShadow.rmiss deleted file mode 100644 index 0378e62..0000000 --- a/ray_tracing_anyhit/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#include "raycommon.glsl" - -layout(location = 1) rayPayloadInEXT shadowPayload prd; - -void main() -{ - prd.isHit = false; -} diff --git a/ray_tracing_anyhit/shaders/raytrace_0.rahit b/ray_tracing_anyhit/shaders/raytrace_0.rahit deleted file mode 100644 index b65dc9e..0000000 --- a/ray_tracing_anyhit/shaders/raytrace_0.rahit +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_GOOGLE_include_directive : enable - -#define PAYLOAD_0 -#include "raytrace_rahit.glsl" diff --git a/ray_tracing_anyhit/shaders/raytrace_1.rahit b/ray_tracing_anyhit/shaders/raytrace_1.rahit deleted file mode 100644 index dbb32ac..0000000 --- a/ray_tracing_anyhit/shaders/raytrace_1.rahit +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_GOOGLE_include_directive : enable - -#define PAYLOAD_1 -#include "raytrace_rahit.glsl" diff --git a/ray_tracing_anyhit/shaders/raytrace_rahit.glsl b/ray_tracing_anyhit/shaders/raytrace_rahit.glsl deleted file mode 100644 index 2f2e38e..0000000 --- a/ray_tracing_anyhit/shaders/raytrace_rahit.glsl +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -//#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "random.glsl" -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -#ifdef PAYLOAD_0 -layout(location = 0) rayPayloadInEXT hitPayload prd; -#elif defined(PAYLOAD_1) -layout(location = 1) rayPayloadInEXT shadowPayload prd; -#endif - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -// clang-format on - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - if(mat.illum != 4) - return; - - if(mat.dissolve == 0.0) - ignoreIntersectionEXT; - else if(rnd(prd.seed) > mat.dissolve) - ignoreIntersectionEXT; -} diff --git a/ray_tracing_anyhit/shaders/vert_shader.vert b/ray_tracing_anyhit/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_anyhit/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_anyhit/shaders/wavefront.glsl b/ray_tracing_anyhit/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_anyhit/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_ao/CMakeLists.txt b/ray_tracing_ao/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_ao/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_ao/README.md b/ray_tracing_ao/README.md deleted file mode 100644 index 2f90fd4..0000000 --- a/ray_tracing_ao/README.md +++ /dev/null @@ -1,476 +0,0 @@ -# G-Buffer and Ambient Occlusion - Tutorial - -![](images/ray_tracing_ao.png) - -## Tutorial ([Setup](../docs/setup.md)) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -This extension to the tutorial is showing how G-Buffers from the fragment shader, can be used in a compute shader to cast ambient occlusion rays using -ray queries [(GLSL_EXT_ray_query)](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_query.txt). - -We are using some previous extensions of the tutorial to create this one. - -* The usage of `ray query` is from [ray_tracing_rayquery](../ray_tracing_rayquery) -* The notion of accumulated frames, is comming from [ray_tracing_jitter_cam](../ray_tracing_jitter_cam) -* The creation and dispatch of compute shader was inspired from [ray_tracing_animation](../ray_tracing_animation) - -## Workflow - -The fragment shader no longer just writes to an RGBA buffer for the colored image, but also writes to a G-buffer the position and normal for each fragment. -Then a compute shader takes the G-buffer and sends random ambient occlusion rays into the hemisphere formed by position and normal. - -![](images/Hemisphere_sampling.png) - -The compute shader reads and stores into the AO buffer. It reads the previous information to cumulate it over time and store the accumulated value. Finally, the post shader is slightly modified to include the AO buffer and multiply its value by the RGBA color frame before tonemapping and writing to the frame buffer. - -![](images/Tuto_Ao_workflow.png) - -The following are the buffers are they can be seen in [NSight Graphics](https://developer.nvidia.com/nsight-graphics). - -![](images/buffers.png) - -## G-Buffer - -The framework was already writing to G-Buffers, but was writing to a single `VK_FORMAT_R32G32B32A32_SFLOAT` buffer. In the function `HelloVulkan::createOffscreenRender()`, we will add the creation of two new buffers. One `VK_FORMAT_R32G32B32A32_SFLOAT` to store the position and normal and one `VK_FORMAT_R32_SFLOAT` for the ambient occlusion. - -~~~~ C++ - // The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed) - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler); - m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - m_debug.setObjectName(m_gBuffer.image, "G-Buffer"); - } - - // The ambient occlusion result (r32) - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler); - m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - m_debug.setObjectName(m_aoBuffer.image, "aoBuffer"); - } -~~~~ - -Add the `nvvk::Texture` members for `m_gBuffer` and `m_aoBuffer` to the class and to the destructor function, and don't forget to set the right image layout. - -The render pass for the fragment shader will need two color buffers, therefore we need to modify the offscreen framebuffer attachments. - -``` - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, - m_gBuffer.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; -``` - -### Renderpass - -This means that the renderpass in `main()` will have to be modified as well. The clear color will need to have 3 entries (2 color + 1 depth) - -``` - std::array clearValues{}; -``` - -Since the clear value will be re-used by the offscreen (3 attachments) and the post/UI (2 attachments), we will set the clear values in each section. - -``` - // Offscreen render pass - { - clearValues[1].color = {{0, 0, 0, 0}}; - clearValues[2].depthStencil = {1.0f, 0}; -``` - -``` - // 2nd rendering pass: tone mapper, UI - { - clearValues[1].depthStencil = {1.0f, 0}; -``` - -### Fragment shader - -The fragment shader can now write into two different textures. - -We are omitting the code to compress and decompress the XYZ normal to and from a single unsigned integer, but you can find the code in [raycommon.glsl](shaders/raycommon.glsl) - -``` -// Outgoing -layout(location = 0) out vec4 o_color; -layout(location = 1) out vec4 o_gbuffer; -... - - o_gbuffer.rgba = vec4(worldPos, uintBitsToFloat(CompressUnitVec(N))); -``` - -## Ray Tracing - -As for the [ray_tracing_rayquery](../ray_tracing_rayquery) sample, we use the VK_KHR_acceleration_structure extension to generate the ray tracing acceleration structure, while the ray tracing itself is carried out in a compute shader. This section remains unchanged compared to the rayquery example. - -## Compute Shader - -The compute shader will take the G-Buffer containing the position and normal and will randomly shot rays in the hemisphere defined by the normal. - -### Descriptor - -The shader takes two inputs, the G-Buffer and the TLAS, and has one output, the AO buffer: - -~~~ C++ -//-------------------------------------------------------------------------------------------------- -// Compute shader descriptor -// -void HelloVulkan::createCompDescriptors() -{ - m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer - m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO - m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS - - m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); - m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); - m_compDescSet = nvvk::allocateDescriptorSet(m_device, m_compDescPool, m_compDescSetLayout); -} -~~~ - -### Descriptor Update - -The function `updateCompDescriptors()` is done separately from the descriptor, because it can happen that some resources -are re-created, therefore their address isn't valid and we need to set those values back to the decriptors. For example, -when resizing the window and the G-Buffer and AO buffer are resized. - -~~~ C++ -//-------------------------------------------------------------------------------------------------- -// Setting up the values to the descriptors -// -void HelloVulkan::updateCompDescriptors() -{ - std::vector writes; - writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor)); - writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor)); - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo)); - - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} -~~~~ - -### Pipeline - -The creation of the pipeline is identical to the animation tutorial, but we will push a structure to the pushConstant -instead of a single float. - -The information we will push, will allow us to play with the AO algorithm. - -~~~~ C++ -struct AoControl -{ - float rtao_radius{2.0f}; // Length of the ray - int rtao_samples{4}; // Nb samples at each iteration - float rtao_power{2.0f}; // Darkness is stronger for more hits - int rtao_distance_based{1}; // Attenuate based on distance - int frame{0}; // Current frame -}; -~~~~ - -### Dispatch Compute - -The first thing we are doing in the `runCompute` is to call `updateFrame()` (see [jitter cam](../ray_tracing_jitter_cam)). -This sets the current frame index, which allows us to accumulate AO samples over time. - -Next, we are adding a `VkImageMemoryBarrier` to be sure the G-Buffer image is ready to be read from the compute shader. - -~~~~ C++ - // Adding a barrier to be sure the fragment has finished writing to the G-Buffer - // before the compute shader is using the buffer - VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; - VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; - imgMemBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - imgMemBarrier.image = m_gBuffer.image; - imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; - imgMemBarrier.subresourceRange = range; - - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier); -~~~~ - -Following is the call to dispatch the compute shader - -~~~~ C++ - // Preparing for the compute shader - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr); - - - // Sending the push constant information - aoControl.frame = m_frame; - vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl); - - // Dispatching the shader - vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1); -~~~~ - -Then we are adding a final barrier to make sure the compute shader is done -writing the AO so that the fragment shader (post) can use it. - -~~~~ C++ - // Adding a barrier to be sure the compute shader has finished - // writing to the AO buffer before the post shader is using it - imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - imgMemBarrier.image = m_aoBuffer.image; - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier); -~~~~ - -## Update Frame - -The following functions were added to tell which frame we are rendering. -The function `updateFrame()` is called only once per frame, and we are doing this in runCompute()/ - -And the `resetFrame()` should be called whenever the image is changed, like in `onResize()` or -after modifying the GUI related to the AO. - -~~~~ C++ -//-------------------------------------------------------------------------------------------------- -// If the camera matrix has changed, resets the frame otherwise, increments frame. -// -void HelloVulkan::updateFrame() -{ - static glm::mat4 refCamMatrix; - static float fov = 0; - - auto& m = CameraManip.getMatrix(); - auto f = CameraManip.getFov(); - if(refCamMatrix != m || f != fov) - { - resetFrame(); - refCamMatrix = m; - fov = f; - } - - m_frame++; -} - -void HelloVulkan::resetFrame() -{ - m_frame = -1; -} -~~~~ - -## Compute Shader (code) - -The compute shader, which can be found under [ao.comp](shaders/ao.comp) is using the [ray query](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_query.txt) extension. - -The first thing in `main()` is to check if the invocation is not exceeding the size of the image. - -~~~~C -void main() -{ - float occlusion = 0.0; - - ivec2 size = imageSize(inImage); - // Check if not outside boundaries - if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y) - return; -~~~~ - -The seed of the random number sequence is initialized using the TEA algorithm, while the random number themselves will be generated using PCG. -This is a fine when many random numbers are generated from this seed, but tea isn't a random -number generator and if you use only one sample per pixel, you will see correlation and the AO will not look fine because it won't -sample uniformly the entire hemisphere. This could be resolved if the seed was kept over frame, but for this example, we will use -this simple technique. - -~~~~C - // Initialize the random number - uint seed = tea(size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, frame_number); -~~~~ - -Secondly, we are retrieving the position and normal stored in the fragment shader. - -~~~~C - // Retrieving position and normal - vec4 gBuffer = imageLoad(inImage, ivec2(gl_GlobalInvocationID.xy)); -~~~~ - -The G-Buffer was cleared and we will sample the hemisphere only if a fragment was rendered. In `w` -we stored the compressed normal, which is nonzero only if a normal was actually stored into the pixel. -Note that while this compression introduces some level of quantization, it does not result in visible artifacts in this example. - -The `OffsetRay` can be found in [raycommon.glsl](shaders/raycommon.glsl), and was taken from [Ray Tracing Gems, Ch. 6](http://www.realtimerendering.com/raytracinggems/unofficial_RayTracingGems_v1.7.pdf). This is a convenient way to avoid finding manually the appropriate minimum offset. - -~~~~C - // Shooting rays only if a fragment was rendered - if(gBuffer != vec4(0)) - { - vec3 origin = gBuffer.xyz; - vec3 normal = decompress_unit_vec(floatBitsToUint(gBuffer.w)); - vec3 direction; - - // Move origin slightly away from the surface to avoid self-occlusion - origin = OffsetRay(origin, normal); -~~~~ - -From the normal, we generate the basis (tangent and bitangent) which will be used for sampling. -The function `compute_default_basis` is also in [raycommon.glsl](shaders/raycommon.glsl) - -~~~~C - // Finding the basis (tangent and bitangent) from the normal - vec3 n, tangent, bitangent; - compute_default_basis(normal, tangent, bitangent); -~~~~ - -Then we are sampling the hemisphere `rtao_samples` time, using a [cosine weighted sampling](https://people.cs.kuleuven.be/~philip.dutre/GI/) - -~~~~C - // Sampling hemiphere n-time - for(int i = 0; i < rtao_samples; i++) - { - // Cosine sampling - float r1 = rnd(seed); - float r2 = rnd(seed); - float sq = sqrt(1.0 - r2); - float phi = 2 * M_PI * r1; - vec3 direction = vec3(cos(phi) * sq, sin(phi) * sq, sqrt(r2)); - direction = direction.x * tangent + direction.y * bitangent + direction.z * normal; - // Initializes a ray query object but does not start traversal - rayQueryEXT rayQuery; - - occlusion += TraceRay(rayQuery, origin, direction); - } -~~~~ - -The function `TraceRay` is a very simple way to send a shadow ray using ray query. -For any type of shadow, we don't care which object we hit as long as the ray hit something -before maximum length. For this, we can set the flag to `gl_RayFlagsTerminateOnFirstHitEXT`. -But there is a case where we may want to know the distance of the hit from the closest hit, in this case -the flag is set to `gl_RayFlagsNoneEXT`. - -The function returns 0 if it didn't hit anything or a value between 0 and 1, depending on how close the -hit was. It will return 1 if `rtao_distance_based == 0` - -~~~~C -//---------------------------------------------------------------------------- -// Tracing a ray and returning the weight based on the distance of the hit -// -float TraceRay(in rayQueryEXT rayQuery, in vec3 origin, in vec3 direction) -{ - uint flags = gl_RayFlagsNoneEXT; - if(rtao_distance_based == 0) - flags = gl_RayFlagsTerminateOnFirstHitEXT; - - rayQueryInitializeEXT(rayQuery, topLevelAS, flags, 0xFF, origin, 0.0f, direction, rtao_radius); - - // Start traversal: return false if traversal is complete - while(rayQueryProceedEXT(rayQuery)) - { - } - - // Returns type of committed (true) intersection - if(rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT) - { - // Got an intersection == Shadow - if(rtao_distance_based == 0) - return 1; - float length = 1 - (rayQueryGetIntersectionTEXT(rayQuery, true) / rtao_radius); - return length; // * length; - } - - return 0; -} -~~~~ - -Similar to the camera jitter example, the result is stored at frame 0 and accumulate over time. - -~~~~C - // Writting out the AO - if(frame_number == 0) - { - imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(occlusion)); - } - else - { - // Accumulating over time - float old_ao = imageLoad(outImage, ivec2(gl_GlobalInvocationID.xy)).x; - float new_result = mix(old_ao, occlusion, 1.0f / float(frame_number)); - imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(new_result)); - } -} -~~~~ - -## IMGUI addition - -In `main()`, we have added some controls to modify the behavior of how the AO is computed. Immediately after the call to `renderUI`, -the following code as added. - -~~~~ C++ -ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once); -if(ImGui::CollapsingHeader("Ambient Occlusion")) -{ - bool changed{false}; - changed |= ImGui::SliderFloat("Radius", &aoControl.rtao_radius, 0, 5); - changed |= ImGui::SliderInt("Rays per Pixel", &aoControl.rtao_samples, 1, 64); - changed |= ImGui::SliderFloat("Power", &aoControl.rtao_power, 1, 5); - changed |= ImGui::Checkbox("Distanced Based", (bool*)&aoControl.rtao_distance_based); - if(changed) - helloVk.resetFrame(); -} -~~~~ - -We have also have added `AoControl aoControl;` somwhere in main() and passing the information to the execution of the compute shader. - -~~~~C -// Rendering Scene -{ - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - helloVk.runCompute(cmdBuf, aoControl); -} -~~~~ - -## Post shader - -The post shader will combine the result of the fragment (color) and the result of the compute shader (ao). -In `createPostDescriptor` we will need to add the descriptor - -~~~~C -m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); -~~~~ - -And the equivalent in `updatePostDescriptorSet()` - -~~~~C -writes.push_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor)); -~~~~ - -### Post.frag - -Then in the fragment shader of the post process, we need to add the layout for the AO image - -~~~~C -layout(set = 0, binding = 1) uniform sampler2D aoTxt; -~~~~ - -And the image will now be returned as the following - -~~~~C - vec4 color = texture(noisyTxt, uv); - float ao = texture(aoTxt, uv).x; - - fragColor = pow(color * ao, vec4(gamma)); -~~~~ diff --git a/ray_tracing_ao/hello_vulkan.cpp b/ray_tracing_ao/hello_vulkan.cpp deleted file mode 100644 index f0454e4..0000000 --- a/ray_tracing_ao/hello_vulkan.cpp +++ /dev/null @@ -1,866 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, VK_SHADER_STAGE_FRAGMENT_BIT); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - VkPipelineColorBlendAttachmentState res{}; - res.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - res.colorBlendOp = VK_BLEND_OP_ADD; - gpb.addBlendAttachmentState(res); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_gBuffer); - m_alloc.destroy(m_aoBuffer); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - // Compute - vkDestroyPipeline(m_device, m_compPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_compPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_compDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_compDescSetLayout, nullptr); - - // #VKRay - m_rtBuilder.destroy(); - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateCompDescriptors(); - resetFrame(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_gBuffer); - m_alloc.destroy(m_aoBuffer); - m_alloc.destroy(m_offscreenDepth); - - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - m_debug.setObjectName(m_offscreenColor.image, "offscreen"); - } - - // The G-Buffer (rgba32f) - position(xyz) / normal(w-compressed) - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32G32B32A32_SFLOAT, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_gBuffer = m_alloc.createTexture(image, ivInfo, sampler); - m_gBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - m_debug.setObjectName(m_gBuffer.image, "G-Buffer"); - } - - // The ambient occlusion result (r32) - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, VK_FORMAT_R32_SFLOAT, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - m_aoBuffer = m_alloc.createTexture(image, ivInfo, sampler); - m_aoBuffer.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - m_debug.setObjectName(m_aoBuffer.image, "aoBuffer"); - } - - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_gBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_aoBuffer.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = - nvvk::createRenderPass(m_device, {m_offscreenColorFormat, m_offscreenColorFormat}, // RGBA + G-Buffer - m_offscreenDepthFormat, 1, true, true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_gBuffer.descriptor.imageView, - m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = static_cast(attachments.size()); - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - std::vector writes; - writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor)); - writes.emplace_back(m_postDescSetLayoutBind.makeWrite(m_postDescSet, 1, &m_aoBuffer.descriptor)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - - -////////////////////////////////////////////////////////////////////////// -// Compute shader from ANIMATION tutorial -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Compute shader descriptor -// -void HelloVulkan::createCompDescriptors() -{ - m_compDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] G-Buffer - m_compDescSetLayoutBind.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [out] AO - m_compDescSetLayoutBind.addBinding(2, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_COMPUTE_BIT); // [in] TLAS - - m_compDescSetLayout = m_compDescSetLayoutBind.createLayout(m_device); - m_compDescPool = m_compDescSetLayoutBind.createPool(m_device, 1); - m_compDescSet = nvvk::allocateDescriptorSet(m_device, m_compDescPool, m_compDescSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the values to the descriptors -// -void HelloVulkan::updateCompDescriptors() -{ - std::vector writes; - writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 0, &m_gBuffer.descriptor)); - writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 1, &m_aoBuffer.descriptor)); - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - writes.emplace_back(m_compDescSetLayoutBind.makeWrite(m_compDescSet, 2, &descASInfo)); - - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline: shader ... -// -void HelloVulkan::createCompPipelines() -{ - // pushing time - VkPushConstantRange push_constants = {VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl)}; - VkPipelineLayoutCreateInfo plCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - plCreateInfo.setLayoutCount = 1; - plCreateInfo.pSetLayouts = &m_compDescSetLayout; - plCreateInfo.pushConstantRangeCount = 1; - plCreateInfo.pPushConstantRanges = &push_constants; - vkCreatePipelineLayout(m_device, &plCreateInfo, nullptr, &m_compPipelineLayout); - - VkComputePipelineCreateInfo cpCreateInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; - cpCreateInfo.layout = m_compPipelineLayout; - cpCreateInfo.stage = nvvk::createShaderStageInfo(m_device, nvh::loadFile("spv/ao.comp.spv", true, defaultSearchPaths, true), - VK_SHADER_STAGE_COMPUTE_BIT); - - vkCreateComputePipelines(m_device, {}, 1, &cpCreateInfo, nullptr, &m_compPipeline); - - vkDestroyShaderModule(m_device, cpCreateInfo.stage.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Running compute shader -// -#define GROUP_SIZE 16 // Same group size as in compute shader -void HelloVulkan::runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl) -{ - updateFrame(); - - // Stop by default after 100'000 samples - if(m_frame * aoControl.rtao_samples > aoControl.max_samples) - return; - - m_debug.beginLabel(cmdBuf, "Compute"); - - // Adding a barrier to be sure the fragment has finished writing to the G-Buffer - // before the compute shader is using the buffer - VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; - VkImageMemoryBarrier imgMemBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; - imgMemBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - imgMemBarrier.image = m_gBuffer.image; - imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; - imgMemBarrier.subresourceRange = range; - - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier); - - - // Preparing for the compute shader - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_compPipelineLayout, 0, 1, &m_compDescSet, 0, nullptr); - - - // Sending the push constant information - aoControl.frame = m_frame; - vkCmdPushConstants(cmdBuf, m_compPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(AoControl), &aoControl); - - // Dispatching the shader - vkCmdDispatch(cmdBuf, (m_size.width + (GROUP_SIZE - 1)) / GROUP_SIZE, (m_size.height + (GROUP_SIZE - 1)) / GROUP_SIZE, 1); - - - // Adding a barrier to be sure the compute shader has finished - // writing to the AO buffer before the post shader is using it - imgMemBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - imgMemBarrier.image = m_aoBuffer.image; - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, nullptr, 0, nullptr, 1, &imgMemBarrier); - - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -// Reset from JITTER CAM tutorial -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// If the camera matrix has changed, resets the frame otherwise, increments frame. -// -void HelloVulkan::updateFrame() -{ - static glm::mat4 refCamMatrix; - static float fov = 0; - - auto& m = CameraManip.getMatrix(); - auto f = CameraManip.getFov(); - if(refCamMatrix != m || f != fov) - { - resetFrame(); - refCamMatrix = m; - fov = f; - } - - m_frame++; -} - -void HelloVulkan::resetFrame() -{ - m_frame = -1; -} diff --git a/ray_tracing_ao/hello_vulkan.h b/ray_tracing_ao/hello_vulkan.h deleted file mode 100644 index 42a5de3..0000000 --- a/ray_tracing_ao/hello_vulkan.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - -struct AoControl -{ - float rtao_radius{2.0f}; // Length of the ray - int rtao_samples{4}; // Nb samples at each iteration - float rtao_power{3.0f}; // Darkness is stronger for more hits - int rtao_distance_based{1}; // Attenuate based on distance - int frame{0}; // Current frame - int max_samples{100'000}; // Max samples before it stops -}; - - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - nvvk::Texture m_gBuffer; - nvvk::Texture m_aoBuffer; - - // #Tuto_rayquery - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - - - // #Tuto_animation - void createCompDescriptors(); - void updateCompDescriptors(); - void createCompPipelines(); - void runCompute(VkCommandBuffer cmdBuf, AoControl& aoControl); - - nvvk::DescriptorSetBindings m_compDescSetLayoutBind; - VkDescriptorPool m_compDescPool; - VkDescriptorSetLayout m_compDescSetLayout; - VkDescriptorSet m_compDescSet; - VkPipeline m_compPipeline; - VkPipelineLayout m_compPipelineLayout; - - // #Tuto_jitter_cam - void updateFrame(); - void resetFrame(); - int m_frame{0}; -}; diff --git a/ray_tracing_ao/images/Hemisphere_sampling.png b/ray_tracing_ao/images/Hemisphere_sampling.png deleted file mode 100644 index 4146458..0000000 Binary files a/ray_tracing_ao/images/Hemisphere_sampling.png and /dev/null differ diff --git a/ray_tracing_ao/images/Tuto_Ao_workflow.png b/ray_tracing_ao/images/Tuto_Ao_workflow.png deleted file mode 100644 index 769fbd0..0000000 Binary files a/ray_tracing_ao/images/Tuto_Ao_workflow.png and /dev/null differ diff --git a/ray_tracing_ao/images/buffers.png b/ray_tracing_ao/images/buffers.png deleted file mode 100644 index a25795a..0000000 Binary files a/ray_tracing_ao/images/buffers.png and /dev/null differ diff --git a/ray_tracing_ao/images/ray_tracing_ao.png b/ray_tracing_ao/images/ray_tracing_ao.png deleted file mode 100644 index d257c6c..0000000 Binary files a/ray_tracing_ao/images/ray_tracing_ao.png and /dev/null differ diff --git a/ray_tracing_ao/main.cpp b/ray_tracing_ao/main.cpp deleted file mode 100644 index c65d9d6..0000000 --- a/ray_tracing_ao/main.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures); // Ray tracing in compute shader - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - glm::mat4 t = glm::translate(glm::mat4(1), glm::vec3{0, 0.0, 0}); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), t); - //helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - - // Need the Top level AS - helloVk.updateDescriptorSet(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - helloVk.createCompDescriptors(); - helloVk.updateCompDescriptors(); - helloVk.createCompPipelines(); - - - glm::vec4 clearColor = glm::vec4(0, 0, 0, 0); - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - - AoControl aoControl; - - - // Main loop - while(!glfwWindowShouldClose(window)) - { - try - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - - renderUI(helloVk); - ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if(ImGui::CollapsingHeader("Ambient Occlusion")) - { - bool changed{false}; - changed |= ImGui::SliderFloat("Radius", &aoControl.rtao_radius, 0, 5); - changed |= ImGui::SliderInt("Rays per Pixel", &aoControl.rtao_samples, 1, 64); - changed |= ImGui::SliderFloat("Power", &aoControl.rtao_power, 1, 5); - changed |= ImGui::InputInt("Max Samples", &aoControl.max_samples); - changed |= ImGui::Checkbox("Distanced Based", (bool*)&aoControl.rtao_distance_based); - if(changed) - helloVk.resetFrame(); - } - - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - - - // Offscreen render pass - { - clearValues[1].color = {{0, 0, 0, 0}}; - clearValues[2].depthStencil = {1.0f, 0}; - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = (uint32_t)clearValues.size(); - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - helloVk.runCompute(cmdBuf, aoControl); - } - } - - // 2nd rendering pass: tone mapper, UI - { - clearValues[1].depthStencil = {1.0f, 0}; - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - catch(const std::system_error& e) - { - if(e.code().value() == VK_ERROR_DEVICE_LOST) - { -#if _WIN32 - MessageBoxA(nullptr, e.what(), "Fatal Error", MB_ICONERROR | MB_OK | MB_DEFBUTTON1); -#endif - } - std::cout << e.what() << std::endl; - return e.code().value(); - } - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_ao/shaders/ao.comp b/ray_tracing_ao/shaders/ao.comp deleted file mode 100644 index c0dc8c9..0000000 --- a/ray_tracing_ao/shaders/ao.comp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_EXT_ray_tracing : enable -#extension GL_EXT_ray_query : enable -#include "raycommon.glsl" - - -const int GROUP_SIZE = 16; -layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE) in; -layout(set = 0, binding = 0, rgba32f) uniform image2D inImage; -layout(set = 0, binding = 1, r32f) uniform image2D outImage; -layout(set = 0, binding = 2) uniform accelerationStructureEXT topLevelAS; - - -// See AoControl -layout(push_constant) uniform params_ -{ - float rtao_radius; - int rtao_samples; - float rtao_power; - int rtao_distance_based; - int frame_number; - int max_samples; -}; - - -//---------------------------------------------------------------------------- -// Tracing a ray and returning the weight based on the distance of the hit -// -float TraceRay(in rayQueryEXT rayQuery, in vec3 origin, in vec3 direction) -{ - uint flags = gl_RayFlagsNoneEXT; - if(rtao_distance_based == 0) - flags = gl_RayFlagsTerminateOnFirstHitEXT; - - rayQueryInitializeEXT(rayQuery, topLevelAS, flags, 0xFF, origin, 0.0f, direction, rtao_radius); - - // Start traversal: return false if traversal is complete - while(rayQueryProceedEXT(rayQuery)) - { - } - - // Returns type of committed (true) intersection - if(rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT) - { - // Got an intersection == Shadow - if(rtao_distance_based == 0) - return 1; - float length = 1 - (rayQueryGetIntersectionTEXT(rayQuery, true) / rtao_radius); - return length; // * length; - } - - return 0; -} - - -void main() -{ - float occlusion = 0.0; - - ivec2 size = imageSize(inImage); - // Check if not outside boundaries - if(gl_GlobalInvocationID.x >= size.x || gl_GlobalInvocationID.y >= size.y) - return; - - // Initialize the random number - uint seed = tea(size.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x, frame_number); - - // Retrieving position and normal - vec4 gBuffer = imageLoad(inImage, ivec2(gl_GlobalInvocationID.xy)); - - // Shooting rays only if a fragment was rendered - if(gBuffer != vec4(0)) - { - vec3 origin = gBuffer.xyz; - vec3 normal = DecompressUnitVec(floatBitsToUint(gBuffer.w)); - vec3 direction; - - // Move origin slightly away from the surface to avoid self-occlusion - origin = OffsetRay(origin, normal); - - // Finding the basis (tangent and bitangent) from the normal - vec3 n, tangent, bitangent; - ComputeDefaultBasis(normal, tangent, bitangent); - - // Sampling hemiphere n-time - for(int i = 0; i < rtao_samples; i++) - { - // Cosine sampling - float r1 = rnd(seed); - float r2 = rnd(seed); - float sq = sqrt(1.0 - r2); - float phi = 2 * M_PI * r1; - vec3 direction = vec3(cos(phi) * sq, sin(phi) * sq, sqrt(r2)); - direction = direction.x * tangent + direction.y * bitangent + direction.z * normal; - // Initializes a ray query object but does not start traversal - rayQueryEXT rayQuery; - - occlusion += TraceRay(rayQuery, origin, direction); - } - - // Computing occlusion - occlusion = 1 - (occlusion / rtao_samples); - occlusion = pow(clamp(occlusion, 0, 1), rtao_power); - } - - - // Writting out the AO - if(frame_number == 0) - { - imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(occlusion)); - } - else - { - // Accumulating over time - float old_ao = imageLoad(outImage, ivec2(gl_GlobalInvocationID.xy)).x; - float new_result = mix(old_ao, occlusion, 1.0f / float(frame_number + 1)); - imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), vec4(new_result)); - } -} diff --git a/ray_tracing_ao/shaders/frag_shader.frag b/ray_tracing_ao/shaders/frag_shader.frag deleted file mode 100644 index 88f0e45..0000000 --- a/ray_tracing_ao/shaders/frag_shader.frag +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; -layout(location = 1) out vec4 o_gbuffer; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightDistance; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - lightDistance = d; - } - else - { - L = normalize(pcRaster.lightPosition - vec3(0)); - lightDistance = 10000; - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - diffuse = vec3(1); - // if(mat.textureId >= 0) - // { - // int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - // uint txtId = txtOffset + mat.textureId; - // vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz; - // diffuse *= diffuseTxt; - // } - //lightIntensity = 1; - // Specular - vec3 specular = vec3(0); //computeSpecular(mat, viewDir, L, N); - lightIntensity = 1; - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); - o_gbuffer.rgba = vec4(i_worldPos, uintBitsToFloat(CompressUnitVec(N))); -} diff --git a/ray_tracing_ao/shaders/host_device.h b/ray_tracing_ao/shaders/host_device.h deleted file mode 100644 index a22192e..0000000 --- a/ray_tracing_ao/shaders/host_device.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_ao/shaders/passthrough.vert b/ray_tracing_ao/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_ao/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_ao/shaders/post.frag b/ray_tracing_ao/shaders/post.frag deleted file mode 100644 index cc0857a..0000000 --- a/ray_tracing_ao/shaders/post.frag +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; -layout(set = 0, binding = 1) uniform sampler2D aoTxt; - - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - vec4 color = texture(noisyTxt, uv); - float ao = texture(aoTxt, uv).x; - - fragColor = pow(color * ao, vec4(gamma)); -} diff --git a/ray_tracing_ao/shaders/raycommon.glsl b/ray_tracing_ao/shaders/raycommon.glsl deleted file mode 100644 index 5e4ff63..0000000 --- a/ray_tracing_ao/shaders/raycommon.glsl +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -//- -// This utility compresses a normal(x,y,z) to a uint and decompresses it - - -#define C_Stack_Max 3.402823466e+38f -uint CompressUnitVec(vec3 nv) -{ - // map to octahedron and then flatten to 2D (see 'Octahedron Environment Maps' by Engelhardt & Dachsbacher) - if((nv.x < C_Stack_Max) && !isinf(nv.x)) - { - const float d = 32767.0f / (abs(nv.x) + abs(nv.y) + abs(nv.z)); - int x = int(roundEven(nv.x * d)); - int y = int(roundEven(nv.y * d)); - if(nv.z < 0.0f) - { - const int maskx = x >> 31; - const int masky = y >> 31; - const int tmp = 32767 + maskx + masky; - const int tmpx = x; - x = (tmp - (y ^ masky)) ^ maskx; - y = (tmp - (tmpx ^ maskx)) ^ masky; - } - uint packed = (uint(y + 32767) << 16) | uint(x + 32767); - if(packed == ~0u) - return ~0x1u; - return packed; - } - else - { - return ~0u; - } -} - -float ShortToFloatM11(const int v) // linearly maps a short 32767-32768 to a float -1-+1 //!! opt.? -{ - return (v >= 0) ? (uintBitsToFloat(0x3F800000u | (uint(v) << 8)) - 1.0f) : - (uintBitsToFloat((0x80000000u | 0x3F800000u) | (uint(-v) << 8)) + 1.0f); -} -vec3 DecompressUnitVec(uint packed) -{ - if(packed != ~0u) // sanity check, not needed as isvalid_unit_vec is called earlier - { - int x = int(packed & 0xFFFFu) - 32767; - int y = int(packed >> 16) - 32767; - const int maskx = x >> 31; - const int masky = y >> 31; - const int tmp0 = 32767 + maskx + masky; - const int ymask = y ^ masky; - const int tmp1 = tmp0 - (x ^ maskx); - const int z = tmp1 - ymask; - float zf; - if(z < 0) - { - x = (tmp0 - ymask) ^ maskx; - y = tmp1 ^ masky; - zf = uintBitsToFloat((0x80000000u | 0x3F800000u) | (uint(-z) << 8)) + 1.0f; - } - else - { - zf = uintBitsToFloat(0x3F800000u | (uint(z) << 8)) - 1.0f; - } - return normalize(vec3(ShortToFloatM11(x), ShortToFloatM11(y), zf)); - } - else - { - return vec3(C_Stack_Max); - } -} - - -//------------------------------------------------------------------------------------------------- -// Avoiding self intersections (see Ray Tracing Gems, Ch. 6) -// -vec3 OffsetRay(in vec3 p, in vec3 n) -{ - const float intScale = 256.0f; - const float floatScale = 1.0f / 65536.0f; - const float origin = 1.0f / 32.0f; - - ivec3 of_i = ivec3(intScale * n.x, intScale * n.y, intScale * n.z); - - vec3 p_i = vec3(intBitsToFloat(floatBitsToInt(p.x) + ((p.x < 0) ? -of_i.x : of_i.x)), - intBitsToFloat(floatBitsToInt(p.y) + ((p.y < 0) ? -of_i.y : of_i.y)), - intBitsToFloat(floatBitsToInt(p.z) + ((p.z < 0) ? -of_i.z : of_i.z))); - - return vec3(abs(p.x) < origin ? p.x + floatScale * n.x : p_i.x, // - abs(p.y) < origin ? p.y + floatScale * n.y : p_i.y, // - abs(p.z) < origin ? p.z + floatScale * n.z : p_i.z); -} - - -//////////////////////////// AO ////////////////////////////////////// -#define EPS 0.05 -const float M_PI = 3.141592653589; - -void ComputeDefaultBasis(const vec3 normal, out vec3 x, out vec3 y) -{ - // ZAP's default coordinate system for compatibility - vec3 z = normal; - const float yz = -z.y * z.z; - y = normalize(((abs(z.z) > 0.99999f) ? vec3(-z.x * z.y, 1.0f - z.y * z.y, yz) : vec3(-z.x * z.z, yz, 1.0f - z.z * z.z))); - - x = cross(y, z); -} - -//------------------------------------------------------------------------------------------------- -// Random -//------------------------------------------------------------------------------------------------- - - -// Generate a random unsigned int from two unsigned int values, using 16 pairs -// of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis, -// "GPU Random Numbers via the Tiny Encryption Algorithm" -uint tea(uint val0, uint val1) -{ - uint v0 = val0; - uint v1 = val1; - uint s0 = 0; - - for(uint n = 0; n < 16; n++) - { - s0 += 0x9e3779b9; - v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); - v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); - } - - return v0; -} - -uvec2 pcg2d(uvec2 v) -{ - v = v * 1664525u + 1013904223u; - - v.x += v.y * 1664525u; - v.y += v.x * 1664525u; - - v = v ^ (v >> 16u); - - v.x += v.y * 1664525u; - v.y += v.x * 1664525u; - - v = v ^ (v >> 16u); - - return v; -} - -// Generate a random unsigned int in [0, 2^24) given the previous RNG state -// using the Numerical Recipes linear congruential generator -uint lcg(inout uint prev) -{ - uint LCG_A = 1664525u; - uint LCG_C = 1013904223u; - prev = (LCG_A * prev + LCG_C); - return prev & 0x00FFFFFF; -} - -// Generate a random float in [0, 1) given the previous RNG state -float rnd(inout uint seed) -{ - return (float(lcg(seed)) / float(0x01000000)); -} diff --git a/ray_tracing_ao/shaders/vert_shader.vert b/ray_tracing_ao/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_ao/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_ao/shaders/wavefront.glsl b/ray_tracing_ao/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_ao/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_callable/CMakeLists.txt b/ray_tracing_callable/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_callable/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_callable/README.md b/ray_tracing_callable/README.md deleted file mode 100644 index 93c642f..0000000 --- a/ray_tracing_callable/README.md +++ /dev/null @@ -1,198 +0,0 @@ -# Callable Shaders - Tutorial - -![](images/callable.png) -Author: [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/) - -## Tutorial ([Setup](../docs/setup.md)) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - - -Ray tracing allow to use [callable shaders](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap8.html#shaders-callable) -in ray-generation, closest-hit, miss or another callable shader stage. -It is similar to an indirect function call, whitout having to link those shaders with the executable program. - -(insert setup.md.html here) - - -## Data Storage - -Data can only access data passed in to the callable from parent stage. There will be only one structure pass at a time and should be declared like for payload. - -In the parent stage, using the `callableDataEXT` storage qualifier, it could be declared like: - -~~~~ C++ -layout(location = 0) callableDataEXT rayLight cLight; -~~~~ - -where `rayLight` struct is defined in a shared file. - -~~~~ C++ -struct rayLight -{ - vec3 inHitPosition; - float outLightDistance; - vec3 outLightDir; - float outIntensity; -}; -~~~~ - -And in the incoming callable shader, you must use the `callableDataInEXT` storage qualifier. - -~~~~ C++ -layout(location = 0) callableDataInEXT rayLight cLight; -~~~~ - -## Execution - -To execute one of the callable shader, the parent stage need to call `executeCallableEXT`. - -The first parameter is the SBT record index, the second one correspond to the 'location' index. - -Example of how it is called. - -~~~~ C++ -executeCallableEXT(pushC.lightType, 0); -~~~~ - - -## Adding Callable Shaders to the SBT - -### Create Shader Modules - -In `HelloVulkan::createRtPipeline()`, immediately after adding the closest-hit shader, we will add -3 callable shaders, for each type of light. - -First create the shader modules -~~~~ C++ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eCall0, - eCall1, - eCall2, - eShaderGroupCount - }; - - ... - // Call0 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; - stages[eCall0] = stage; - // Call1 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; - stages[eCall1] = stage; - // Call2 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; - stages[eCall2] = stage; -~~~~ - -Then 3 groups of callable shaders and the stages that goes with it. - -~~~~ C++ - // Callable shaders - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = eCall0; - m_rtShaderGroups.push_back(group); - group.generalShader = eCall1; - m_rtShaderGroups.push_back(group); - group.generalShader = eCall2; - m_rtShaderGroups.push_back(group); -~~~~ - - - -#### Shaders - -Here are the source of all shaders - -* [light_point.rcall](shaders/light_point.rcall) -* [light_spot.rcall](shaders/light_spot.rcall) -* [light_inf.rcall](shaders/light_inf.rcall) - - -### Shading Binding Table - -In this example, we will use the `nvvk::SBTWrapper`. It is using the information to create the ray tracing pipeline, to -create the buffers for the shading binding table. - -In the `hello_vulkan.h` header, include the wrapper and add a new member. - -~~~~C -#include "nvvk/sbtwrapper_vk.hpp" -... -nvvk::SBTWrapper m_sbtWrapper; -~~~~ - -In `HelloVulkan::initRayTracing()`, initialize it the following way. - -~~~~C -m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); -~~~~ - -In `HelloVulkan::createRtPipeline()`, immediately after creating the pipeline call to `vkCreateRayTracingPipelinesKHR()`, -create the SBT with the following command. - -~~~~C - m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); -~~~~ - - - -In `HelloVulkan::raytrace()`, we have to tell where the callable shader starts. Since they were added after the hit shader, we have in the SBT the following. - -![SBT](images/sbt.png) - -The SBT wrapper class give back the information we need. So instead of computing the various offsets, we can get directly the -`VkStridedDeviceAddressRegionKHR` for each group type. - -~~~~ C++ - auto& regions = m_sbtWrapper.getRegions(); - vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); -~~~~ - -## Calling the Callable Shaders - -In the closest-hit shader, instead of having a if-else case, we can now call directly the right shader base on the type of light. - -~~~~ C++ -cLight.inHitPosition = worldPos; -//#define DONT_USE_CALLABLE -#if defined(DONT_USE_CALLABLE) - // Point light - if(pushC.lightType == 0) - { - vec3 lDir = pushC.lightPosition - cLight.inHitPosition; - float lightDistance = length(lDir); - cLight.outIntensity = pushC.lightIntensity / (lightDistance * lightDistance); - cLight.outLightDir = normalize(lDir); - cLight.outLightDistance = lightDistance; - } - else if(pushC.lightType == 1) - { - vec3 lDir = pushC.lightPosition - cLight.inHitPosition; - cLight.outLightDistance = length(lDir); - cLight.outIntensity = - pushC.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); - cLight.outLightDir = normalize(lDir); - float theta = dot(cLight.outLightDir, normalize(-pushC.lightDirection)); - float epsilon = pushC.lightSpotCutoff - pushC.lightSpotOuterCutoff; - float spotIntensity = clamp((theta - pushC.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); - cLight.outIntensity *= spotIntensity; - } - else // Directional light - { - cLight.outLightDir = normalize(-pushC.lightDirection); - cLight.outIntensity = 1.0; - cLight.outLightDistance = 10000000; - } -#else - executeCallableEXT(pushC.lightType, 0); -#endif -~~~~ diff --git a/ray_tracing_callable/hello_vulkan.cpp b/ray_tracing_callable/hello_vulkan.cpp deleted file mode 100644 index ab449f8..0000000 --- a/ray_tracing_callable/hello_vulkan.cpp +++ /dev/null @@ -1,895 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_sbtWrapper.destroy(); - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); - - m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eCall0, - eCall1, - eCall2, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - // Call0 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; - stages[eCall0] = stage; - // Call1 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; - stages[eCall1] = stage; - // Call2 - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; - stages[eCall2] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - - // Callable shaders - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = eCall0; - m_rtShaderGroups.push_back(group); - group.generalShader = eCall1; - m_rtShaderGroups.push_back(group); - group.generalShader = eCall2; - m_rtShaderGroups.push_back(group); - - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR - | VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - - m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightDirection = m_pcRaster.lightDirection; - m_pcRay.lightSpotCutoff = m_pcRaster.lightSpotCutoff; - m_pcRay.lightSpotOuterCutoff = m_pcRaster.lightSpotOuterCutoff; - m_pcRay.lightType = m_pcRaster.lightType; - - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR - | VK_SHADER_STAGE_CALLABLE_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - auto& regions = m_sbtWrapper.getRegions(); - vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); - - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing_callable/hello_vulkan.h b/ray_tracing_callable/hello_vulkan.h deleted file mode 100644 index f712c8b..0000000 --- a/ray_tracing_callable/hello_vulkan.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" -#include "nvvk/sbtwrapper_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // lightPosition - {0}, // instanceId to retrieve the transformation matrix - {-1.f, -1.f, -1.f}, // lightDirection - {100.f}, // lightIntensity - {cos(glm::radians(12.5f))}, // lightSpotCutoff - {cos(glm::radians(17.5f))}, // lightSpotOuterCutoff - {0} // lightType 0: point, 1: infinite - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - - PushConstantRay m_pcRay{}; - - nvvk::SBTWrapper m_sbtWrapper; -}; diff --git a/ray_tracing_callable/images/callable.png b/ray_tracing_callable/images/callable.png deleted file mode 100644 index 64248cf..0000000 Binary files a/ray_tracing_callable/images/callable.png and /dev/null differ diff --git a/ray_tracing_callable/images/sbt.png b/ray_tracing_callable/images/sbt.png deleted file mode 100644 index 139f752..0000000 Binary files a/ray_tracing_callable/images/sbt.png and /dev/null differ diff --git a/ray_tracing_callable/main.cpp b/ray_tracing_callable/main.cpp deleted file mode 100644 index 73976db..0000000 --- a/ray_tracing_callable/main.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Spot", &helloVk.m_pcRaster.lightType, 1); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 2); - - if(helloVk.m_pcRaster.lightType < 2) - ImGui::SliderFloat3("Light Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - if(helloVk.m_pcRaster.lightType > 0) - ImGui::SliderFloat3("Light Direction", &helloVk.m_pcRaster.lightDirection.x, -1.f, 1.f); - if(helloVk.m_pcRaster.lightType < 2) - ImGui::SliderFloat("Light Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 500.f); - if(helloVk.m_pcRaster.lightType == 1) - { - float dCutoff = glm::degrees(acos(helloVk.m_pcRaster.lightSpotCutoff)); - float dOutCutoff = glm::degrees(acos(helloVk.m_pcRaster.lightSpotOuterCutoff)); - ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f); - ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f); - dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff; - - helloVk.m_pcRaster.lightSpotCutoff = cos(glm::radians(dCutoff)); - helloVk.m_pcRaster.lightSpotOuterCutoff = cos(glm::radians(dOutCutoff)); - } - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_callable/shaders/frag_shader.frag b/ray_tracing_callable/shaders/frag_shader.frag deleted file mode 100644 index 2ff6dd9..0000000 --- a/ray_tracing_callable/shaders/frag_shader.frag +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 LightDir; - float lightIntensity; - - // Point light - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float lightDistance = length(lDir); - lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance); - LightDir = normalize(lDir); - } - else if(pcRaster.lightType == 1) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float lightDistance = length(lDir); - lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance); - LightDir = normalize(lDir); - float theta = dot(LightDir, normalize(-pcRaster.lightDirection)); - float epsilon = pcRaster.lightSpotCutoff - pcRaster.lightSpotOuterCutoff; - float spotIntensity = clamp((theta - pcRaster.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); - lightIntensity *= spotIntensity; - } - else // Directional light - { - LightDir = normalize(-pcRaster.lightDirection); - lightIntensity = 1.0; - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, LightDir, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, LightDir, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_callable/shaders/host_device.h b/ray_tracing_callable/shaders/host_device.h deleted file mode 100644 index 85a55f5..0000000 --- a/ray_tracing_callable/shaders/host_device.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - vec3 lightDirection; - float lightIntensity; - float lightSpotCutoff; - float lightSpotOuterCutoff; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - vec3 lightDirection; - float lightSpotCutoff; - float lightSpotOuterCutoff; - int lightType; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_callable/shaders/light_inf.rcall b/ray_tracing_callable/shaders/light_inf.rcall deleted file mode 100644 index 08fa09c..0000000 --- a/ray_tracing_callable/shaders/light_inf.rcall +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 core -#extension GL_EXT_ray_tracing : enable -#extension GL_GOOGLE_include_directive : enable -#include "raycommon.glsl" - -layout(location = 0) callableDataInEXT rayLight cLight; - -layout(push_constant) uniform Constants -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - vec3 lightDirection; - float lightSpotCutoff; - float lightSpotOuterCutoff; - int lightType; -}; - -void main() -{ - cLight.outLightDistance = 10000000; - cLight.outIntensity = 1.0; - cLight.outLightDir = normalize(-lightDirection); -} diff --git a/ray_tracing_callable/shaders/light_point.rcall b/ray_tracing_callable/shaders/light_point.rcall deleted file mode 100644 index 014db67..0000000 --- a/ray_tracing_callable/shaders/light_point.rcall +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 core -#extension GL_EXT_ray_tracing : enable -#extension GL_GOOGLE_include_directive : enable -#include "raycommon.glsl" - -layout(location = 0) callableDataInEXT rayLight cLight; - -layout(push_constant) uniform Constants -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - vec3 lightDirection; - float lightSpotCutoff; - float lightSpotOuterCutoff; - int lightType; -}; - -void main() -{ - vec3 lDir = lightPosition - cLight.inHitPosition; - cLight.outLightDistance = length(lDir); - cLight.outIntensity = lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); - cLight.outLightDir = normalize(lDir); -} diff --git a/ray_tracing_callable/shaders/light_spot.rcall b/ray_tracing_callable/shaders/light_spot.rcall deleted file mode 100644 index 78813f9..0000000 --- a/ray_tracing_callable/shaders/light_spot.rcall +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 core -#extension GL_EXT_ray_tracing : enable -#extension GL_GOOGLE_include_directive : enable -#include "raycommon.glsl" - -layout(location = 0) callableDataInEXT rayLight cLight; - -layout(push_constant) uniform Constants -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - vec3 lightDirection; - float lightSpotCutoff; - float lightSpotOuterCutoff; - int lightType; -}; - -void main() -{ - vec3 lDir = lightPosition - cLight.inHitPosition; - cLight.outLightDistance = length(lDir); - cLight.outIntensity = lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); - cLight.outLightDir = normalize(lDir); - float theta = dot(cLight.outLightDir, normalize(-lightDirection)); - float epsilon = lightSpotCutoff - lightSpotOuterCutoff; - float spotIntensity = clamp((theta - lightSpotOuterCutoff) / epsilon, 0.0, 1.0); - cLight.outIntensity *= spotIntensity; -} diff --git a/ray_tracing_callable/shaders/passthrough.vert b/ray_tracing_callable/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_callable/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_callable/shaders/post.frag b/ray_tracing_callable/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_callable/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_callable/shaders/raycommon.glsl b/ray_tracing_callable/shaders/raycommon.glsl deleted file mode 100644 index 35d6ba8..0000000 --- a/ray_tracing_callable/shaders/raycommon.glsl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; - -struct rayLight -{ - vec3 inHitPosition; - float outLightDistance; - vec3 outLightDir; - float outIntensity; -}; diff --git a/ray_tracing_callable/shaders/raytrace.rchit b/ray_tracing_callable/shaders/raytrace.rchit deleted file mode 100644 index b268e4f..0000000 --- a/ray_tracing_callable/shaders/raytrace.rchit +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -layout(location = 0) callableDataEXT rayLight cLight; - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - - cLight.inHitPosition = worldPos; -//#define DONT_USE_CALLABLE -#if defined(DONT_USE_CALLABLE) - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - cLight.inHitPosition; - float lightDistance = length(lDir); - cLight.outIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - cLight.outLightDir = normalize(lDir); - cLight.outLightDistance = lightDistance; - } - else if(pcRay.lightType == 1) - { - vec3 lDir = pcRay.lightPosition - cLight.inHitPosition; - cLight.outLightDistance = length(lDir); - cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance); - cLight.outLightDir = normalize(lDir); - float theta = dot(cLight.outLightDir, normalize(-pcRay.lightDirection)); - float epsilon = pcRay.lightSpotCutoff - pcRay.lightSpotOuterCutoff; - float spotIntensity = clamp((theta - pcRay.lightSpotOuterCutoff) / epsilon, 0.0, 1.0); - cLight.outIntensity *= spotIntensity; - } - else // Directional light - { - cLight.outLightDir = normalize(-pcRay.lightDirection); - cLight.outIntensity = 1.0; - cLight.outLightDistance = 10000000; - } -#else - executeCallableEXT(pcRay.lightType, 0); -#endif - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, cLight.outLightDir, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, cLight.outLightDir) > 0) - { - float tMin = 0.001; - float tMax = cLight.outLightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = cLight.outLightDir; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, cLight.outLightDir, worldNrm); - } - } - - prd.hitValue = vec3(cLight.outIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_callable/shaders/raytrace.rgen b/ray_tracing_callable/shaders/raytrace.rgen deleted file mode 100644 index 4802cd0..0000000 --- a/ray_tracing_callable/shaders/raytrace.rgen +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0)); -} diff --git a/ray_tracing_callable/shaders/raytrace.rmiss b/ray_tracing_callable/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_callable/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_callable/shaders/raytraceShadow.rmiss b/ray_tracing_callable/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_callable/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_callable/shaders/vert_shader.vert b/ray_tracing_callable/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_callable/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_callable/shaders/wavefront.glsl b/ray_tracing_callable/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_callable/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_indirect_scissor/CMakeLists.txt b/ray_tracing_indirect_scissor/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_indirect_scissor/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_indirect_scissor/README.md b/ray_tracing_indirect_scissor/README.md deleted file mode 100644 index 74e07b2..0000000 --- a/ray_tracing_indirect_scissor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# NVIDIA Vulkan Trace Rays Indirect Tutorial -This is an extension of the [Vulkan ray tracing tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -We will discuss the `vkCmdTraceRaysIndirectKHR` command, which allows the -`width`, `height`, and `depth` of a trace ray command to be specifed by a -buffer on the device, rather than directly by the host. As a demonstration, -this example will add colorful lanterns to the scene that add their own light -and shadows, with a finite radius of effect. A compute shader will calculate -scissor rectangles for each lantern, and an indirect trace rays command will -dispatch rays for lanterns only within those scissor rectangles. - -[

LINK TO FULL TUTORIAL

](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tuto_indirect_scissor.md.html) - -![](../docs/Images/indirect_scissor/intro.png) - diff --git a/ray_tracing_indirect_scissor/hello_vulkan.cpp b/ray_tracing_indirect_scissor/hello_vulkan.cpp deleted file mode 100644 index b7926f8..0000000 --- a/ray_tracing_indirect_scissor/hello_vulkan.cpp +++ /dev/null @@ -1,1397 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -#include - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - -// Add a light-emitting colored lantern to the scene. May only be called before TLAS build. -void HelloVulkan::addLantern(glm::vec3 pos, glm::vec3 color, float brightness, float radius) -{ - assert(m_lanternCount == 0); // Indicates TLAS build has not happened yet. - - m_lanterns.push_back({pos, color, brightness, radius}); -} - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - m_alloc.destroy(m_rtSBTBuffer); - - vkDestroyDescriptorPool(m_device, m_lanternIndirectDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_lanternIndirectDescSetLayout, nullptr); - vkDestroyPipeline(m_device, m_lanternIndirectCompPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_lanternIndirectCompPipelineLayout, nullptr); - m_alloc.destroy(m_lanternIndirectBuffer); - m_alloc.destroy(m_lanternVertexBuffer); - m_alloc.destroy(m_lanternIndexBuffer); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -// Tesselate a sphere as a list of triangles; return its -// vertices and indices as reference arguments. -void HelloVulkan::fillLanternVerts(std::vector& vertices, std::vector& indices) -{ - // Create a spherical lantern model by recursively tesselating an octahedron. - struct VertexIndex - { - glm::vec3 vertex; - uint32_t index; // Keep track of this vert's _eventual_ index in vertices. - }; - struct Triangle - { - VertexIndex vert0, vert1, vert2; - }; - - VertexIndex posX{{m_lanternModelRadius, 0, 0}, 0}; - VertexIndex negX{{-m_lanternModelRadius, 0, 0}, 1}; - VertexIndex posY{{0, m_lanternModelRadius, 0}, 2}; - VertexIndex negY{{0, -m_lanternModelRadius, 0}, 3}; - VertexIndex posZ{{0, 0, m_lanternModelRadius}, 4}; - VertexIndex negZ{{0, 0, -m_lanternModelRadius}, 5}; - uint32_t vertexCount = 6; - - // Initial triangle list is octahedron. - std::vector triangles{{posX, posY, posZ}, {posX, posY, negZ}, {posX, negY, posZ}, {posX, negY, negZ}, - {negX, posY, posZ}, {negX, posY, negZ}, {negX, negY, posZ}, {negX, negY, negZ}}; - - // Recursion: every iteration, convert the current model to a new - // model by breaking each triangle into 4 triangles. - for(int recursions = 0; recursions < 3; ++recursions) - { - std::vector new_triangles; - for(const Triangle& t : triangles) - { - // Split each of three edges in half, then fixup the - // length of the midpoint to match m_lanternModelRadius. - // Record the index the new vertices will eventually have in vertices. - VertexIndex v01{m_lanternModelRadius * glm::normalize(t.vert0.vertex + t.vert1.vertex), vertexCount++}; - VertexIndex v12{m_lanternModelRadius * glm::normalize(t.vert1.vertex + t.vert2.vertex), vertexCount++}; - VertexIndex v02{m_lanternModelRadius * glm::normalize(t.vert0.vertex + t.vert2.vertex), vertexCount++}; - - // Old triangle becomes 4 new triangles. - new_triangles.push_back({t.vert0, v01, v02}); - new_triangles.push_back({t.vert1, v01, v12}); - new_triangles.push_back({t.vert2, v02, v12}); - new_triangles.push_back({v01, v02, v12}); - } - triangles = std::move(new_triangles); - } - - vertices.resize(vertexCount); - indices.clear(); - indices.reserve(triangles.size() * 3); - - // Write out the vertices to the vertices vector, and - // connect the tessellated triangles with indices in the indices vector. - for(const Triangle& t : triangles) - { - vertices[t.vert0.index] = t.vert0.vertex; - vertices[t.vert1.index] = t.vert1.vertex; - vertices[t.vert2.index] = t.vert2.vertex; - indices.push_back(t.vert0.index); - indices.push_back(t.vert1.index); - indices.push_back(t.vert2.index); - } -} - -// Create the BLAS storing triangles for the spherical lantern model. This fills in -// m_lanternVertexBuffer: packed VkBuffer of vec3 -// m_lanternIndexBuffer: packed VkBuffer of 32-bit indices -// m_lanternBlasInput: BLAS for spherical lantern -// -// NOTE: A more elegant way to do this is to use a procedural hit group instead, -// then, this BLAS can just be one AABB. I wanted to avoid introducing the new -// concept of intersection shaders here. -void HelloVulkan::createLanternModel() -{ - std::vector vertices; - std::vector indices; - fillLanternVerts(vertices, indices); - - // Upload vertex and index data to buffers. - auto usageFlags = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - auto memFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - - auto vertexBytes = vertices.size() * sizeof vertices[0]; - m_lanternVertexBuffer = m_alloc.createBuffer(vertexBytes, usageFlags, memFlags); - void* map = m_alloc.map(m_lanternVertexBuffer); - memcpy(map, vertices.data(), vertexBytes); - m_alloc.unmap(m_lanternVertexBuffer); - - auto indexBytes = indices.size() * sizeof indices[0]; - m_lanternIndexBuffer = m_alloc.createBuffer(indexBytes, usageFlags, memFlags); - map = m_alloc.map(m_lanternIndexBuffer); - memcpy(map, indices.data(), indexBytes); - m_alloc.unmap(m_lanternIndexBuffer); - - // Package vertex and index buffers as BlasInput. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternVertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, m_lanternIndexBuffer.buffer); - - auto maxPrimitiveCount = uint32_t(indices.size() / 3); - - // Describe buffer as packed array of float vec3. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(glm::vec3); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = uint32_t(vertices.size()) - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - m_lanternBlasInput.asGeometry.emplace_back(asGeom); - m_lanternBlasInput.asBuildOffsetInfo.emplace_back(offset); -} - -//-------------------------------------------------------------------------------------------------- -// -// Build the array of BLAS in m_rtBuilder. There are `m_objModel.size() + 1`-many BLASes. -// The first `m_objModel.size()` are used for OBJ model BLASes, and the last one -// is used for the lanterns (model generated at runtime). -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size() + 1); - - // Add OBJ models. - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - - // Add lantern model. - createLanternModel(); - m_lanternBlasId = allBlas.size(); - allBlas.emplace_back(m_lanternBlasInput); - - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -// Build the TLAS in m_rtBuilder. Requires that the BLASes were already built and -// that all ObjInstance and lanterns have been added. One instance with hitGroupId=0 -// is created for every OBJ instance, and one instance with hitGroupId=1 for each lantern. -// -// gl_InstanceCustomIndexEXT will be the index of the obj id or lantern in m_instances or -// m_lanterns respectively. -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - assert(m_lanternCount == 0); - m_lanternCount = m_lanterns.size(); - - std::vector tlas; - tlas.reserve(m_instances.size() + m_lanternCount); - - // Add the OBJ instances. - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - - // Add lantern instances. - for(int i = 0; i < static_cast(m_lanterns.size()); ++i) - { - VkAccelerationStructureInstanceKHR lanternInstance; - lanternInstance.transform = nvvk::toTransformMatrixKHR(glm::translate(glm::mat4(1), m_lanterns[i].position)); - lanternInstance.instanceCustomIndex = i; - lanternInstance.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(uint32_t(m_lanternBlasId)); - lanternInstance.instanceShaderBindingTableRecordOffset = 1; // Next hit group is for lanterns. - lanternInstance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - lanternInstance.mask = 0xFF; - tlas.emplace_back(lanternInstance); - } - - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure, output image, and lanterns array buffer. -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - // Lantern buffer - m_rtDescSetLayoutBind.addBinding(eLanterns, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - assert(m_lanternCount > 0); - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkDescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, eLanterns, &lanternBufferInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -// Shader list: -// -// 0 ====== Ray Generation Shaders ===================================================== -// -// Raygen shader: Ray generation shader. Casts primary rays from camera to scene. -// -// 1 ====== Miss Shaders =============================================================== -// -// Miss shader 0: Miss shader when casting primary rays. Fill in clear color. -// -// 2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// -// Miss shader 1: Miss shader when casting shadow rays towards main light. -// Reports no shadow. -// -// 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// -// Miss shader 2: Miss shader when casting shadow rays towards a lantern. -// Reports no lantern hit (-1). -// -// 4 ====== Hit Groups for Primary Rays (sbtRecordOffset=0) ============================ -// -// chit shader 0: Closest hit shader for primary rays hitting OBJ instances -// (hitGroupId=0). Casts shadow ray (to sky light or to lantern, -// depending on pass number) and returns specular -// and diffuse light to add to output image. -// -// 5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// -// chit shader 1: Closest hit shader for primary rays hitting lantern instances -// (hitGroupId=1). Returns color value to replace the current -// image pixel color with (lanterns are self-illuminating). -// -// 6 - - - - Hit Groups for Lantern Shadow Rays (sbtRecordOffset=2) - - - - - - - - - - - -// -// chit shader 2: Closest hit shader for OBJ instances hit when casting shadow -// rays to a lantern. Returns -1 to report that the shadow ray -// failed to reach the targetted lantern. -// -// 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// -// chit shader 3: Closest hit shader for lantern instances hit when casting shadow -// rays to a lantern. Returns the gl_CustomInstanceIndexEXT [lantern -// number] of the lantern hit. -// -// 8 ===================================================================================== -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMissShd, - eMissLantern, - eClosestHit, - eClosestHitLantern, - eClosestHitLanternShdObj, - eClosestHitLanternShd, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss shader 0 invoked when a primary ray doesn't hit geometry. Fills in clear color. - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // Miss shader 1 is invoked when a shadow ray (for the main scene light) - // misses the geometry. It simply indicates that no occlusion has been found. - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMissShd] = stage; - // Miss shader 2 is invoked when a shadow ray for lantern lighting misses the - // lantern. It shouldn't be invoked, but I include it just in case. - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMissLantern] = stage; - // OBJ Primary Ray Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - - // Lantern Primary Ray Hit Group - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/lantern.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHitLantern] = stage; - - // OBJ Lantern Shadow Ray Hit Group - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowObj.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHitLanternShdObj] = stage; - - - // Lantern Lantern Shadow Ray Hit Group - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternShadowLantern.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHitLanternShd] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMissShd; - m_rtShaderGroups.push_back(group); - - // Lantern Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMissLantern; - m_rtShaderGroups.push_back(group); - - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - - - group.closestHitShader = eClosestHitLantern; - m_rtShaderGroups.push_back(group); - - group.closestHitShader = eClosestHitLanternShdObj; - m_rtShaderGroups.push_back(group); - - group.closestHitShader = eClosestHitLanternShd; - m_rtShaderGroups.push_back(group); - - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// The Shader Binding Table (SBT) -// - getting all shader handles and write them in a SBT buffer -// - Besides exception, this could be always done like this -// -void HelloVulkan::createRtShaderBindingTable() -{ - uint32_t missCount{3}; - uint32_t hitCount{4}; - auto handleCount = 1 + missCount + hitCount; - uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - - // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. - uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); - - m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member - m_missRegion.stride = handleSizeAligned; - m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_hitRegion.stride = handleSizeAligned; - m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - - // Get the shader group handles - uint32_t dataSize = handleCount * handleSize; - std::vector handles(dataSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); - assert(result == VK_SUCCESS); - - // Allocate a buffer for storing the SBT. - VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. - - // Find the SBT addresses of each group - VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; - VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - m_rgenRegion.deviceAddress = sbtAddress; - m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; - m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; - - // Helper to retrieve the handle data - auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; - - // Map the SBT buffer and write in the handles. - auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); - uint8_t* pData{nullptr}; - uint32_t handleIdx{0}; - // Raygen - pData = pSBTBuffer; - memcpy(pData, getHandle(handleIdx++), handleSize); - // Miss - pData = pSBTBuffer + m_rgenRegion.size; - for(uint32_t c = 0; c < missCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_missRegion.stride; - } - // Hit - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; - for(uint32_t c = 0; c < hitCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_hitRegion.stride; - } - - - m_alloc.unmap(m_rtSBTBuffer); - m_alloc.finalizeAndReleaseStaging(); -} - - -//-------------------------------------------------------------------------------------------------- -// The compute shader just needs read/write access to the buffer of LanternIndirectEntry. -void HelloVulkan::createLanternIndirectDescriptorSet() -{ - // Lantern buffer (binding = 0) - m_lanternIndirectDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT); - - m_lanternIndirectDescPool = m_lanternIndirectDescSetLayoutBind.createPool(m_device); - m_lanternIndirectDescSetLayout = m_lanternIndirectDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_lanternIndirectDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_lanternIndirectDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_lanternIndirectDescSet); - - - assert(m_lanternIndirectBuffer.buffer); - VkDescriptorBufferInfo lanternBufferInfo{m_lanternIndirectBuffer.buffer, 0, m_lanternCount * sizeof(LanternIndirectEntry)}; - - std::vector writes; - writes.emplace_back(m_lanternIndirectDescSetLayoutBind.makeWrite(m_lanternIndirectDescSet, 0, &lanternBufferInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - -// Create compute pipeline used to fill m_lanternIndirectBuffer with parameters -// for dispatching the correct number of ray traces. -void HelloVulkan::createLanternIndirectCompPipeline() -{ - // Compile compute shader and package as stage. - VkShaderModule computeShader = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/lanternIndirect.comp.spv", true, defaultSearchPaths, true)); - VkPipelineShaderStageCreateInfo stageInfo{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; - stageInfo.module = computeShader; - stageInfo.pName = "main"; - - // Set up push constant and pipeline layout. - constexpr auto pushSize = static_cast(sizeof(m_lanternIndirectPushConstants)); - VkPushConstantRange pushCRange = {VK_SHADER_STAGE_COMPUTE_BIT, 0, pushSize}; - static_assert(pushSize <= 128, "Spec guarantees only 128 byte push constant"); - VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - layoutInfo.setLayoutCount = 1; - layoutInfo.pSetLayouts = &m_lanternIndirectDescSetLayout; - layoutInfo.pushConstantRangeCount = 1; - layoutInfo.pPushConstantRanges = &pushCRange; - vkCreatePipelineLayout(m_device, &layoutInfo, nullptr, &m_lanternIndirectCompPipelineLayout); - - // Create compute pipeline. - VkComputePipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; - pipelineInfo.stage = stageInfo; - pipelineInfo.layout = m_lanternIndirectCompPipelineLayout; - vkCreateComputePipelines(m_device, {}, 1, &pipelineInfo, nullptr, &m_lanternIndirectCompPipeline); - - vkDestroyShaderModule(m_device, computeShader, nullptr); -} - -// Allocate the buffer used to pass lantern info + ray trace indirect parameters to ray tracer. -// Fill in the lantern info from m_lanterns (indirect info is filled per-frame on device -// using a compute shader). Must be called only after TLAS build. -// -// The buffer is an array of LanternIndirectEntry, entry i is for m_lanterns[i]. -void HelloVulkan::createLanternIndirectBuffer() -{ - assert(m_lanternCount > 0); - assert(m_lanternCount == m_lanterns.size()); - - // m_alloc behind the scenes uses cmdBuf to transfer data to the buffer. - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - - using Usage = VkBufferUsageFlagBits; - m_lanternIndirectBuffer = m_alloc.createBuffer(sizeof(LanternIndirectEntry) * m_lanternCount, - VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT - | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - std::vector entries(m_lanternCount); - for(size_t i = 0; i < m_lanternCount; ++i) - entries[i].lantern = m_lanterns[i]; - vkCmdUpdateBuffer(cmdBuf, m_lanternIndirectBuffer.buffer, 0, entries.size() * sizeof entries[0], entries.data()); - - cmdBufGet.submitAndWait(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -// The raytracing is split into multiple passes: -// -// First pass fills in the initial values for every pixel in the output image. -// Illumination and shadow rays come from the main light. -// -// Subsequently, one lantern pass is run for each lantern in the scene. We run -// a compute shader to calculate a bounding scissor rectangle for each lantern's light -// effect. This is stored in m_lanternIndirectBuffer. Then an indirect trace rays command -// is run for every lantern within its scissor rectangle. The lanterns' light -// contribution is additively blended into the output image. -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - // Before tracing rays, we need to dispatch the compute shaders that - // fill in the ray trace indirect parameters for each lantern pass. - - // First, barrier before, ensure writes aren't visible to previous frame. - VkBufferMemoryBarrier bufferBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - bufferBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - bufferBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - bufferBarrier.buffer = m_lanternIndirectBuffer.buffer; - bufferBarrier.offset = 0; - bufferBarrier.size = m_lanternCount * sizeof m_lanterns[0]; - vkCmdPipelineBarrier(cmdBuf, - VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, // - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // - VkDependencyFlags(0), // - 0, nullptr, 1, &bufferBarrier, 0, nullptr); - - // Bind compute shader, update push constant and descriptors, dispatch compute. - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipeline); - glm::mat4 view = getViewMatrix(); - m_lanternIndirectPushConstants.viewRowX = glm::row(view, 0); - m_lanternIndirectPushConstants.viewRowY = glm::row(view, 1); - m_lanternIndirectPushConstants.viewRowZ = glm::row(view, 2); - m_lanternIndirectPushConstants.proj = getProjMatrix(); - m_lanternIndirectPushConstants.nearZ = nearZ; - m_lanternIndirectPushConstants.screenX = m_size.width; - m_lanternIndirectPushConstants.screenY = m_size.height; - m_lanternIndirectPushConstants.lanternCount = int32_t(m_lanternCount); - vkCmdPushConstants(cmdBuf, m_lanternIndirectCompPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, - sizeof(LanternIndirectPushConstants), &m_lanternIndirectPushConstants); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_lanternIndirectCompPipelineLayout, 0, 1, - &m_lanternIndirectDescSet, 0, nullptr); - vkCmdDispatch(cmdBuf, 1, 1, 1); - - // Ensure compute results are visible when doing indirect ray trace. - bufferBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - bufferBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - vkCmdPipelineBarrier(cmdBuf, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // - VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, // - VkDependencyFlags(0), // - 0, nullptr, 1, &bufferBarrier, 0, nullptr); - - - // Now move on to the actual ray tracing. - m_debug.beginLabel(cmdBuf, "Ray trace"); - - // Initialize push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - m_pcRay.lanternPassNumber = -1; // Global non-lantern pass - m_pcRay.screenX = m_size.width; - m_pcRay.screenY = m_size.height; - m_pcRay.lanternDebug = m_lanternDebug; - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); - - - // Lantern passes, ensure previous pass completed, then add light contribution from each lantern. - for(int i = 0; i < static_cast(m_lanternCount); ++i) - { - // Barrier to ensure previous pass finished. - VkImage offscreenImage{m_offscreenColor.image}; - VkImageSubresourceRange colorRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}; - VkImageMemoryBarrier imageBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; - imageBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - imageBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; - imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageBarrier.image = offscreenImage; - imageBarrier.subresourceRange = colorRange; - imageBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - imageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - vkCmdPipelineBarrier(cmdBuf, - VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, // - VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, // - VkDependencyFlags(0), // - 0, nullptr, 0, nullptr, 1, &imageBarrier); - - // Set lantern pass number. - m_pcRay.lanternPassNumber = i; - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - VkDeviceAddress indirectDeviceAddress = - nvvk::getBufferDeviceAddress(m_device, m_lanternIndirectBuffer.buffer) + i * sizeof(LanternIndirectEntry); - - // Execute lantern pass. - vkCmdTraceRaysIndirectKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, indirectDeviceAddress); - } - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing_indirect_scissor/hello_vulkan.h b/ray_tracing_indirect_scissor/hello_vulkan.h deleted file mode 100644 index d72bc09..0000000 --- a/ray_tracing_indirect_scissor/hello_vulkan.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void addLantern(glm::vec3 pos, glm::vec3 color, float brightness, float radius); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - - glm::mat4 getViewMatrix() { return CameraManip.getMatrix(); } - - static constexpr float nearZ = 0.1f; - glm::mat4 getProjMatrix() - { - const float aspectRatio = m_size.width / static_cast(m_size.height); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, nearZ, 1000.0f); - proj[1][1] *= -1; - return proj; - } - - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Information on each colored lantern illuminating the scene. - struct Lantern - { - glm::vec3 position; - glm::vec3 color; - float brightness{0}; - float radius{0}; // Max world-space distance that light illuminates. - }; - - // Information on each colored lantern, plus the info needed for dispatching the - // indirect ray trace command used to add its brightness effect. - // The dispatched ray trace covers pixels (offsetX, offsetY) to - // (offsetX + indirectCommand.width - 1, offsetY + indirectCommand.height - 1). - struct LanternIndirectEntry - { - // Filled in by the device using a compute shader. - // NOTE: I rely on indirectCommand being the first member. - VkTraceRaysIndirectCommandKHR indirectCommand{}; - int32_t offsetX{0}; - int32_t offsetY{0}; - - // Filled in by the host. - Lantern lantern{}; - }; - - // Array of objects and instances in the scene. Not modifiable after acceleration structure build. - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - // Array of lanterns in scene. Not modifiable after acceleration structure build. - std::vector m_lanterns; - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - -private: - void fillLanternVerts(std::vector& vertices, std::vector& indices); - void createLanternModel(); - -public: - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createLanternIndirectDescriptorSet(); - void createLanternIndirectCompPipeline(); - void createRtShaderBindingTable(); - void createLanternIndirectBuffer(); - - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - // Used to store lantern model, generated at runtime. - const float m_lanternModelRadius = 0.125; - nvvk::Buffer m_lanternVertexBuffer; - nvvk::Buffer m_lanternIndexBuffer; - nvvk::RaytracingBuilderKHR::BlasInput m_lanternBlasInput{}; - - // Index of lantern's BLAS in the BLAS array stored in m_rtBuilder. - size_t m_lanternBlasId; - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind; - VkDescriptorPool m_lanternIndirectDescPool; - VkDescriptorSetLayout m_lanternIndirectDescSetLayout; - VkDescriptorSet m_lanternIndirectDescSet; - VkPipelineLayout m_lanternIndirectCompPipelineLayout; - VkPipeline m_lanternIndirectCompPipeline; - - nvvk::Buffer m_rtSBTBuffer; - VkStridedDeviceAddressRegionKHR m_rgenRegion{}; - VkStridedDeviceAddressRegionKHR m_missRegion{}; - VkStridedDeviceAddressRegionKHR m_hitRegion{}; - VkStridedDeviceAddressRegionKHR m_callRegion{}; - - // Buffer to source vkCmdTraceRaysIndirectKHR indirect parameters and lantern color, - // position, etc. from when doing lantern lighting passes. - nvvk::Buffer m_lanternIndirectBuffer; - VkDeviceSize m_lanternCount = 0; // Set to actual lantern count after TLAS build, as - // that is the point no more lanterns may be added. - - // Push constant for ray tracer. - PushConstantRay m_pcRay{}; - - - // Copied to RtPushConstant::lanternDebug. If true, - // make lantern produce constant light regardless of distance - // so that I can see the screen rectangle coverage. - bool m_lanternDebug = false; - - - // Push constant for compute shader filling lantern indirect buffer. - // Barely fits in 128-byte push constant limit guaranteed by spec. - struct LanternIndirectPushConstants - { - glm::vec4 viewRowX; // First 3 rows of view matrix. - glm::vec4 viewRowY; // Set w=1 implicitly in shader. - glm::vec4 viewRowZ; - - glm::mat4 proj{}; // Perspective matrix - float nearZ{}; // Near plane used to create projection matrix. - - // Pixel dimensions of output image (needed to scale NDC to screen coordinates). - int32_t screenX{}; - int32_t screenY{}; - - // Length of the LanternIndirectEntry array. - int32_t lanternCount{}; - } m_lanternIndirectPushConstants; -}; diff --git a/ray_tracing_indirect_scissor/main.cpp b/ray_tracing_indirect_scissor/main.cpp deleted file mode 100644 index 63e7d26..0000000 --- a/ray_tracing_indirect_scissor/main.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - ImGui::Checkbox("Lantern Debug", &helloVk.m_lanternDebug); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - helloVk.addLantern({8.000f, 1.100f, 3.600f}, {1.0f, 0.0f, 0.0f}, 0.4f, 4.0f); - helloVk.addLantern({8.000f, 0.600f, 3.900f}, {0.0f, 1.0f, 0.0f}, 0.4f, 4.0f); - helloVk.addLantern({8.000f, 1.100f, 4.400f}, {0.0f, 0.0f, 1.0f}, 0.4f, 4.0f); - helloVk.addLantern({1.730f, 1.812f, -1.604f}, {0.0f, 0.4f, 0.4f}, 0.4f, 4.0f); - helloVk.addLantern({1.730f, 1.862f, 1.916f}, {0.0f, 0.2f, 0.4f}, 0.3f, 3.0f); - helloVk.addLantern({-2.000f, 1.900f, -0.700f}, {0.8f, 0.8f, 0.6f}, 0.4f, 3.9f); - helloVk.addLantern({0.100f, 0.080f, -2.392f}, {1.0f, 0.0f, 1.0f}, 0.5f, 5.0f); - helloVk.addLantern({1.948f, 0.080f, 0.598f}, {1.0f, 1.0f, 1.0f}, 0.6f, 6.0f); - helloVk.addLantern({-2.300f, 0.080f, 2.100f}, {0.0f, 0.7f, 0.0f}, 0.6f, 6.0f); - helloVk.addLantern({-1.400f, 4.300f, 0.150f}, {1.0f, 1.0f, 0.0f}, 0.7f, 7.0f); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createLanternIndirectBuffer(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - helloVk.createLanternIndirectDescriptorSet(); - helloVk.createLanternIndirectCompPipeline(); - helloVk.createRtShaderBindingTable(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_indirect_scissor/shaders/LanternIndirectEntry.glsl b/ray_tracing_indirect_scissor/shaders/LanternIndirectEntry.glsl deleted file mode 100644 index 7a42c7d..0000000 --- a/ray_tracing_indirect_scissor/shaders/LanternIndirectEntry.glsl +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct LanternIndirectEntry -{ - // VkTraceRaysIndirectCommandKHR - int indirectWidth; - int indirectHeight; - int indirectDepth; - - // Pixel coordinate of scissor rect upper-left. - int offsetX; - int offsetY; - - // Lantern starts here: - // Can't use vec3 due to alignment. - float x, y, z; - float red, green, blue; - float brightness; - float radius; -}; diff --git a/ray_tracing_indirect_scissor/shaders/frag_shader.frag b/ray_tracing_indirect_scissor/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_indirect_scissor/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_indirect_scissor/shaders/host_device.h b/ray_tracing_indirect_scissor/shaders/host_device.h deleted file mode 100644 index d62bf44..0000000 --- a/ray_tracing_indirect_scissor/shaders/host_device.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1, // Ray tracer output image - eLanterns = 2 // All lanterns -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; - - // -1 if this is the full-screen pass. Otherwise, this pass is to add light - // from lantern number lanternPassNumber. We use this to lookup trace indirect - // parameters in m_lanternIndirectBuffer. - int lanternPassNumber; - - // Pixel dimensions of the output image. - int screenX; - int screenY; - - // See m_lanternDebug. - int lanternDebug; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_indirect_scissor/shaders/lantern.rchit b/ray_tracing_indirect_scissor/shaders/lantern.rchit deleted file mode 100644 index 38ed2db..0000000 --- a/ray_tracing_indirect_scissor/shaders/lantern.rchit +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#include "raycommon.glsl" - -// Closest hit shader invoked when a primary ray hits a lantern. - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(binding = 2, set = 0) buffer LanternArray { LanternIndirectEntry lanterns[]; } lanterns; - -// clang-format on - -void main() -{ - // Just look up this lantern's color. Self-illuminating, so no lighting calculations. - LanternIndirectEntry lantern = lanterns.lanterns[nonuniformEXT(gl_InstanceCustomIndexEXT)]; - prd.hitValue = vec3(lantern.red, lantern.green, lantern.blue); - prd.additiveBlending = false; -} diff --git a/ray_tracing_indirect_scissor/shaders/lanternIndirect.comp b/ray_tracing_indirect_scissor/shaders/lanternIndirect.comp deleted file mode 100644 index 73fc181..0000000 --- a/ray_tracing_indirect_scissor/shaders/lanternIndirect.comp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_GOOGLE_include_directive : enable - -// Compute shader for filling in raytrace indirect parameters for each lantern -// based on the current camera position (passed as view and proj matrix in -// push constant). -// -// Designed to be dispatched with only one work group; it alone fills in -// the entire lantern array (of length lanternCount, in also push constant). - -#define LOCAL_SIZE 128 -layout(local_size_x = LOCAL_SIZE, local_size_y = 1, local_size_z = 1) in; - -#include "LanternIndirectEntry.glsl" - -layout(binding = 0, set = 0) buffer LanternArray -{ - LanternIndirectEntry lanterns[]; -} -lanterns; - -layout(push_constant) uniform Constants -{ - vec4 viewRowX; - vec4 viewRowY; - vec4 viewRowZ; - mat4 proj; - float nearZ; - int screenX; - int screenY; - int lanternCount; -} -pushC; - -// Copy the technique of "2D Polyhedral Bounds of a Clipped, -// Perspective-Projected 3D Sphere" M. Mara M. McGuire -// http://jcgt.org/published/0002/02/05/paper.pdf -// to compute a screen-space rectangle covering the given Lantern's -// light radius-of-effect. Result is in screen (pixel) coordinates. -void getScreenCoordBox(in LanternIndirectEntry lantern, out ivec2 lower, out ivec2 upper); - -// Use the xyz and radius of lanterns[i] plus the transformation matrices -// in pushC to fill in the offset and indirect parameters of lanterns[i] -// (defines the screen rectangle that this lantern's light is bounded in). -void fillIndirectEntry(int i) -{ - LanternIndirectEntry lantern = lanterns.lanterns[i]; - ivec2 lower, upper; - getScreenCoordBox(lantern, lower, upper); - - lanterns.lanterns[i].indirectWidth = max(0, upper.x - lower.x); - lanterns.lanterns[i].indirectHeight = max(0, upper.y - lower.y); - lanterns.lanterns[i].indirectDepth = 1; - lanterns.lanterns[i].offsetX = lower.x; - lanterns.lanterns[i].offsetY = lower.y; -} - -void main() -{ - for(int i = int(gl_LocalInvocationID.x); i < pushC.lanternCount; i += LOCAL_SIZE) - { - fillIndirectEntry(i); - } -} - -// Functions below modified from the paper. -float square(float a) -{ - return a * a; -} - -void getBoundsForAxis(in bool xAxis, in vec3 center, in float radius, in float nearZ, in mat4 projMatrix, out vec3 U, out vec3 L) -{ - bool trivialAccept = (center.z + radius) < nearZ; // Entirely in back of nearPlane (Trivial Accept) - vec3 a = xAxis ? vec3(1, 0, 0) : vec3(0, 1, 0); - - // given in coordinates (a,z), where a is in the direction of the vector a, and z is in the standard z direction - vec2 projectedCenter = vec2(dot(a, center), center.z); - vec2 bounds_az[2]; - float tSquared = dot(projectedCenter, projectedCenter) - square(radius); - float t, cLength, costheta = 0, sintheta = 0; - - if(tSquared > 0) - { // Camera is outside sphere - // Distance to the tangent points of the sphere (points where a vector from the camera are tangent to the sphere) (calculated a-z space) - t = sqrt(tSquared); - cLength = length(projectedCenter); - - // Theta is the angle between the vector from the camera to the center of the sphere and the vectors from the camera to the tangent points - costheta = t / cLength; - sintheta = radius / cLength; - } - float sqrtPart = 0.0f; - if(!trivialAccept) - sqrtPart = sqrt(square(radius) - square(nearZ - projectedCenter.y)); - - for(int i = 0; i < 2; ++i) - { - if(tSquared > 0) - { - float x = costheta * projectedCenter.x + -sintheta * projectedCenter.y; - float y = sintheta * projectedCenter.x + costheta * projectedCenter.y; - bounds_az[i] = costheta * vec2(x, y); - } - - if(!trivialAccept && (tSquared <= 0 || bounds_az[i].y > nearZ)) - { - bounds_az[i].x = projectedCenter.x + sqrtPart; - bounds_az[i].y = nearZ; - } - sintheta *= -1; // negate theta for B - sqrtPart *= -1; // negate sqrtPart for B - } - U = bounds_az[0].x * a; - U.z = bounds_az[0].y; - L = bounds_az[1].x * a; - L.z = bounds_az[1].y; -} - -/** Center is in camera space */ -void getBoundingBox(in vec3 center, in float radius, in float nearZ, in mat4 projMatrix, out vec2 ndc_low, out vec2 ndc_high) -{ - vec3 maxXHomogenous, minXHomogenous, maxYHomogenous, minYHomogenous; - getBoundsForAxis(true, center, radius, nearZ, projMatrix, maxXHomogenous, minXHomogenous); - getBoundsForAxis(false, center, radius, nearZ, projMatrix, maxYHomogenous, minYHomogenous); - - vec4 projRow0 = vec4(projMatrix[0][0], projMatrix[1][0], projMatrix[2][0], projMatrix[3][0]); - vec4 projRow1 = vec4(projMatrix[0][1], projMatrix[1][1], projMatrix[2][1], projMatrix[3][1]); - vec4 projRow3 = vec4(projMatrix[0][3], projMatrix[1][3], projMatrix[2][3], projMatrix[3][3]); - - // We only need one coordinate for each point, so we save computation by only calculating x(or y) and w - float maxX_w = dot(vec4(maxXHomogenous, 1.0f), projRow3); - float minX_w = dot(vec4(minXHomogenous, 1.0f), projRow3); - float maxY_w = dot(vec4(maxYHomogenous, 1.0f), projRow3); - float minY_w = dot(vec4(minYHomogenous, 1.0f), projRow3); - - float maxX = dot(vec4(maxXHomogenous, 1.0f), projRow0) / maxX_w; - float minX = dot(vec4(minXHomogenous, 1.0f), projRow0) / minX_w; - float maxY = dot(vec4(maxYHomogenous, 1.0f), projRow1) / maxY_w; - float minY = dot(vec4(minYHomogenous, 1.0f), projRow1) / minY_w; - - // Paper minX, etc. names are misleading, not necessarily min. Fix here. - ndc_low = vec2(min(minX, maxX), min(minY, maxY)); - ndc_high = vec2(max(minX, maxX), max(minY, maxY)); -} - -void getScreenCoordBox(in LanternIndirectEntry lantern, out ivec2 lower, out ivec2 upper) -{ - vec4 lanternWorldCenter = vec4(lantern.x, lantern.y, lantern.z, 1); - vec3 center = vec3(dot(pushC.viewRowX, lanternWorldCenter), dot(pushC.viewRowY, lanternWorldCenter), - dot(pushC.viewRowZ, lanternWorldCenter)); - vec2 ndc_low, ndc_high; - float paperNearZ = -abs(pushC.nearZ); // Paper expected negative nearZ, took 2 days to figure out! - getBoundingBox(center, lantern.radius, paperNearZ, pushC.proj, ndc_low, ndc_high); - - // Convert NDC [-1,+1]^2 coordinates to screen coordinates, and clamp to stay in bounds. - - lower.x = clamp(int((ndc_low.x * 0.5 + 0.5) * pushC.screenX), 0, pushC.screenX); - lower.y = clamp(int((ndc_low.y * 0.5 + 0.5) * pushC.screenY), 0, pushC.screenY); - upper.x = clamp(int((ndc_high.x * 0.5 + 0.5) * pushC.screenX), 0, pushC.screenX); - upper.y = clamp(int((ndc_high.y * 0.5 + 0.5) * pushC.screenY), 0, pushC.screenY); -} diff --git a/ray_tracing_indirect_scissor/shaders/lanternShadow.rmiss b/ray_tracing_indirect_scissor/shaders/lanternShadow.rmiss deleted file mode 100644 index 907b331..0000000 --- a/ray_tracing_indirect_scissor/shaders/lanternShadow.rmiss +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -// Miss shader invoked when tracing shadow rays (rays towards lantern) -// in lantern passes. Misses shouldn't really happen, but if they do, -// report we did not hit any lantern by setting hitLanternInstance = -1. -layout(location = 2) rayPayloadInEXT int hitLanternInstance; - -void main() -{ - hitLanternInstance = -1; -} diff --git a/ray_tracing_indirect_scissor/shaders/lanternShadowLantern.rchit b/ray_tracing_indirect_scissor/shaders/lanternShadowLantern.rchit deleted file mode 100644 index fe7b098..0000000 --- a/ray_tracing_indirect_scissor/shaders/lanternShadowLantern.rchit +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#include "raycommon.glsl" - -// During a lantern pass, this closest hit shader is invoked when -// shadow rays (rays towards lantern) hit a lantern. Report back -// which lantern was hit. - -// clang-format off -layout(location = 2) rayPayloadInEXT int hitLanternInstance; - -// clang-format on - -void main() -{ - hitLanternInstance = gl_InstanceCustomIndexEXT; -} diff --git a/ray_tracing_indirect_scissor/shaders/lanternShadowObj.rchit b/ray_tracing_indirect_scissor/shaders/lanternShadowObj.rchit deleted file mode 100644 index 6f33aa0..0000000 --- a/ray_tracing_indirect_scissor/shaders/lanternShadowObj.rchit +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#include "raycommon.glsl" - -// During a lantern pass, this closest hit shader is invoked when -// shadow rays (rays towards lantern) hit a regular OBJ. Report back -// that no lantern was hit (-1). - -// clang-format off -layout(location = 2) rayPayloadInEXT int hitLanternInstance; - -// clang-format on - -void main() -{ - hitLanternInstance = -1; -} diff --git a/ray_tracing_indirect_scissor/shaders/passthrough.vert b/ray_tracing_indirect_scissor/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_indirect_scissor/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_indirect_scissor/shaders/post.frag b/ray_tracing_indirect_scissor/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_indirect_scissor/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_indirect_scissor/shaders/raycommon.glsl b/ray_tracing_indirect_scissor/shaders/raycommon.glsl deleted file mode 100644 index f20cbc3..0000000 --- a/ray_tracing_indirect_scissor/shaders/raycommon.glsl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "LanternIndirectEntry.glsl" - -struct hitPayload -{ - vec3 hitValue; - bool additiveBlending; -}; diff --git a/ray_tracing_indirect_scissor/shaders/raytrace.rchit b/ray_tracing_indirect_scissor/shaders/raytrace.rchit deleted file mode 100644 index 2886200..0000000 --- a/ray_tracing_indirect_scissor/shaders/raytrace.rchit +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; -layout(location = 2) rayPayloadEXT int hitLanternInstance; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eLanterns) buffer LanternArray { LanternIndirectEntry lanterns[]; } lanterns; - -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - vec3 colorIntensity = vec3(pcRay.lightIntensity); - float lightDistance = 100000.0; - - // ray direction is towards lantern, if in lantern pass. - if(pcRay.lanternPassNumber >= 0) - { - LanternIndirectEntry lantern = lanterns.lanterns[pcRay.lanternPassNumber]; - vec3 lDir = vec3(lantern.x, lantern.y, lantern.z) - worldPos; - lightDistance = length(lDir); - vec3 color = vec3(lantern.red, lantern.green, lantern.blue); - // Lantern light decreases linearly. Not physically accurate, but looks good - // and avoids a hard "edge" at the radius limit. Use a constant value - // if lantern debug is enabled to clearly see the covered screen rectangle. - float distanceFade = pcRay.lanternDebug != 0 ? 0.3 : max(0, (lantern.radius - lightDistance) / lantern.radius); - colorIntensity = color * lantern.brightness * distanceFade; - L = normalize(lDir); - } - // Non-lantern pass may have point light... - else if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - colorIntensity = vec3(pcRay.lightIntensity / (lightDistance * lightDistance)); - L = normalize(lDir); - } - else // or directional light. - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - - // Ordinary shadow from the simple tutorial. - if(pcRay.lanternPassNumber < 0) - { - isShadowed = true; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - } - // Lantern shadow ray. Cast a ray towards the lantern whose lighting is being - // added this pass. Only the closest hit shader for lanterns will set - // hitLanternInstance (payload 2) to non-negative value. - else - { - // Skip ray if no light would be added anyway. - if(colorIntensity == vec3(0)) - { - isShadowed = true; - } - else - { - uint flags = gl_RayFlagsOpaqueEXT; - hitLanternInstance = -1; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 2, // sbtRecordOffset : lantern shadow hit groups start at index 2. - 0, // sbtRecordStride - 2, // missIndex : lantern shadow miss shader is number 2. - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 2 // payload (location = 2) - ); - // Did we hit the lantern we expected? - isShadowed = (hitLanternInstance != pcRay.lanternPassNumber); - } - } - - if(isShadowed) - { - attenuation = 0.1; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = colorIntensity * (attenuation * (diffuse + specular)); - prd.additiveBlending = true; -} diff --git a/ray_tracing_indirect_scissor/shaders/raytrace.rgen b/ray_tracing_indirect_scissor/shaders/raytrace.rgen deleted file mode 100644 index b1a2e85..0000000 --- a/ray_tracing_indirect_scissor/shaders/raytrace.rgen +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 0, binding = eLanterns) buffer LanternArray { LanternIndirectEntry lanterns[]; } lanterns; - -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Global light pass is a full screen rectangle (lower corner 0,0), but - // lantern passes are only run within rectangles that may be offset. - ivec2 pixelOffset = ivec2(0); - if(pcRay.lanternPassNumber >= 0) - { - pixelOffset.x = lanterns.lanterns[pcRay.lanternPassNumber].offsetX; - pixelOffset.y = lanterns.lanterns[pcRay.lanternPassNumber].offsetY; - } - - const ivec2 pixelIntCoord = ivec2(gl_LaunchIDEXT.xy) + pixelOffset; - const vec2 pixelCenter = vec2(pixelIntCoord) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(pcRay.screenX, pcRay.screenY); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - // Lanterns (self-illuminating) and miss shader (constant background color) - // do not use additive blending. Only normal OBJ geometry is additive, - // OBJ closest hit sets this to true. - prd.additiveBlending = false; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - // Either add to or replace output image color based on prd.additiveBlending. - // Global pass always replaces color as it is the first pass. - vec3 oldColor = vec3(0); - if(prd.additiveBlending && pcRay.lanternPassNumber >= 0) - { - oldColor = imageLoad(image, pixelIntCoord).rgb; - } - imageStore(image, pixelIntCoord, vec4(prd.hitValue + oldColor, 1.0)); -} diff --git a/ray_tracing_indirect_scissor/shaders/raytrace.rmiss b/ray_tracing_indirect_scissor/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_indirect_scissor/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_indirect_scissor/shaders/raytraceShadow.rmiss b/ray_tracing_indirect_scissor/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_indirect_scissor/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_indirect_scissor/shaders/vert_shader.vert b/ray_tracing_indirect_scissor/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_indirect_scissor/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_indirect_scissor/shaders/wavefront.glsl b/ray_tracing_indirect_scissor/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_indirect_scissor/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_instances/CMakeLists.txt b/ray_tracing_instances/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_instances/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_instances/README.md b/ray_tracing_instances/README.md deleted file mode 100644 index 3ea2dae..0000000 --- a/ray_tracing_instances/README.md +++ /dev/null @@ -1,171 +0,0 @@ -# NVIDIA Vulkan Ray Tracing Tutorial - -![img](images/instances.png) - - -## Tutorial ([Setup](../docs/setup.md)) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - - -Ray tracing can easily handle having many object instances at once. For instance, a top level acceleration structure can -have many different instances of a bottom level acceleration structure. However, when we have many different objects, we -can run into problems with memory allocation. Many Vulkan implementations support no more than 4096 allocations, while -our current application creates 4 allocations per object (Vertex, Index, and Material), then one for the BLAS. That -means we are hitting the limit with just above 1000 objects. - -(insert setup.md.html here) - -## Many Instances - -First, let's look how the scene would look like when we have just a few objects, with many instances. - -In `main.cpp`, add the following includes: - -~~~~ C++ -#include -~~~~ - -Then replace the calls to `helloVk.loadModel` in `main()` by following, which will create instances of cube and cube_multi. - -~~~~ C++ - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); - 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::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() - std::normal_distribution dis(1.0f, 1.0f); - std::normal_distribution disn(0.05f, 0.05f); - - for(uint32_t n = 0; n < 2000; ++n) - { - float scale = fabsf(disn(gen)); - glm::mat4 mat = - glm::translate(glm::mat4(1),glm::vec3{dis(gen), 2.0f + dis(gen), dis(gen)}); - mat = mat * glm::rotation_mat4_x(dis(gen)); - mat = mat * glm::scale(glm::mat4(1.f),glm::vec3(scale)); - helloVk.m_instances.push_back({mat, n % 2}); - } -~~~~ - - **Note:** - 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. - -## Many Objects - -Instead of creating many instances, create many objects. - -Remove the previous code and replace it with the following - -~~~~ C++ - // Creation of the example - 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::normal_distribution dis(1.0f, 1.0f); - std::normal_distribution disn(0.05f, 0.05f); - for(int n = 0; n < 2000; ++n) - { - float scale = fabsf(disn(gen)); - glm::mat4 mat = glm::translate(glm::mat4(1),glm::vec3{dis(gen), 2.0f + dis(gen), dis(gen)}); - mat = mat * glm::rotation_mat4_x(dis(gen)); - mat = mat * glm::scale(glm::mat4(1.f),glm::vec3(scale)); - - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true), mat); - } - - 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. - -Error | Error: VUID_Undefined
Number of currently valid memory objects is not less than the maximum allowed (4096). --|- -Note | This is the best case; the application can run out of memory and crash if substantially more objects are created (e.g. 20,000) - -## Device Memory Allocator (DMA) - -It is possible to use a memory allocator to fix this issue. - -### `hello_vulkan.h` - -In `hello_vulkan.h`, add the following defines at the top of the file to indicate which allocator to use - -~~~~ C++ -// #VKRay -// Choosing the allocator to use -#define ALLOC_DMA -//#define ALLOC_DEDICATED -//#define ALLOC_VMA -~~~~ - - -Replace the definition of buffers and textures and include the right allocator. - -~~~~ C++ -#if defined(ALLOC_DMA) -#include -using Allocator = nvvk::ResourceAllocatorDma; -#elif defined(ALLOC_VMA) -#include -using Allocator = nvvk::ResourceAllocatorVma; -#else -using Allocator = nvvk::ResourceAllocatorDedicated; -#endif -~~~~ - -And replace the `ResourceAllocatorDedicatednvvk::` by the generic allocator type - -~~~~ C++ -Allocator m_alloc; -~~~~ - -### `hello_vulkan.cpp` - -In the source file there is nothing to change, as all allocators are using -the same API. - - -## Result - -Instead of thousands of allocations, our example will have only 14 allocations. Note that some of these allocations are allocated by Dear ImGui, and not by DMA. These are the 14 objects with blue borders below: - -![Memory](images/VkInstanceNsight1.png) - -Finally, here is the Vulkan Device Memory view from Nsight Graphics: -![VkMemory](images/VkInstanceNsight2.png) - - - -## VMA: Vulkan Memory Allocator - -We can also use the [Vulkan Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)(VMA) from AMD. - -VMA is a submodule under `nvpro_core/third_party` folder. - -VMA is using dedicated memory, so you need to add the following extension to the -creation of the context in `main.cpp`. - -~~~~ C++ - contextInfo.addDeviceExtension(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); -~~~~ - -### hello_vulkan.h - -Enable the VMA define - -~~~~ C++ -#define ALLOC_VMA -~~~~ - -### hello_vulkan.cpp - -VMA requires the implementation of the functions and the following should only be defined once in the entire program, and it should be defined before `#include "hello_vulkan.h"`: - -~~~~ C++ -#define VMA_IMPLEMENTATION -~~~~ - -To see if you are using the VMA allocator, put a break point in `VMAMemoryAllocator::allocMemory()`. \ No newline at end of file diff --git a/ray_tracing_instances/hello_vulkan.cpp b/ray_tracing_instances/hello_vulkan.cpp deleted file mode 100644 index 970a32f..0000000 --- a/ray_tracing_instances/hello_vulkan.cpp +++ /dev/null @@ -1,872 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#define VMA_IMPLEMENTATION - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - m_sbtWrapper.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); - m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); - - // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. - if(m_rtProperties.maxRayRecursionDepth <= 1) - { - throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); - } - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - auto& regions = m_sbtWrapper.getRegions(); - vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); - - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing_instances/hello_vulkan.h b/ray_tracing_instances/hello_vulkan.h deleted file mode 100644 index 9372d5e..0000000 --- a/ray_tracing_instances/hello_vulkan.h +++ /dev/null @@ -1,169 +0,0 @@ - -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -// #VKRay -// -// Choosing the allocator to use -#define ALLOC_DMA -//#define ALLOC_DEDICATED -//#define ALLOC_VMA -#include - -#if defined(ALLOC_DMA) -#include -using Allocator = nvvk::ResourceAllocatorDma; -#elif defined(ALLOC_VMA) -#include -using Allocator = nvvk::ResourceAllocatorVma; -#else -using Allocator = nvvk::ResourceAllocatorDedicated; -#endif - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" -#include "nvvk/sbtwrapper_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - // Allocator for buffer, images, acceleration structures - Allocator m_alloc; - - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - nvvk::SBTWrapper m_sbtWrapper; - - // Push constant for ray tracer - PushConstantRay m_pcRay{}; -}; diff --git a/ray_tracing_instances/images/VkInstanceNsight1.png b/ray_tracing_instances/images/VkInstanceNsight1.png deleted file mode 100644 index 3ded966..0000000 Binary files a/ray_tracing_instances/images/VkInstanceNsight1.png and /dev/null differ diff --git a/ray_tracing_instances/images/VkInstanceNsight2.png b/ray_tracing_instances/images/VkInstanceNsight2.png deleted file mode 100644 index ddf4166..0000000 Binary files a/ray_tracing_instances/images/VkInstanceNsight2.png and /dev/null differ diff --git a/ray_tracing_instances/images/instances.png b/ray_tracing_instances/images/instances.png deleted file mode 100644 index 6ab028c..0000000 Binary files a/ray_tracing_instances/images/instances.png and /dev/null differ diff --git a/ray_tracing_instances/main.cpp b/ray_tracing_instances/main.cpp deleted file mode 100644 index 43d5ab7..0000000 --- a/ray_tracing_instances/main.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -// Utility to time the execution of something resetting the timer -// on each elapse call -// Usage: -// { -// MilliTimer timer; -// ... stuff ... -// double time_elapse = timer.elapse(); -// } -#include - -struct MilliTimer -{ - MilliTimer() { reset(); } - void reset() { startTime = std::chrono::high_resolution_clock::now(); } - double elapse() - { - auto now = std::chrono::high_resolution_clock::now(); - auto t = std::chrono::duration_cast(now - startTime).count() / 1000.0; - startTime = now; - return t; - } - void print() { LOGI(" --> (%5.3f ms)\n", elapse()); } - - std::chrono::high_resolution_clock::time_point startTime; -}; - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - MilliTimer timer; - - // Creation of the example - 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::normal_distribution dis(1.0f, 1.0f); - std::normal_distribution disn(0.05f, 0.05f); - for(uint32_t n = 0; n < 2000; ++n) - { - float scale = fabsf(disn(gen)); - glm::mat4 mat = glm::translate(glm::mat4(1), glm::vec3{dis(gen), 2.0f + dis(gen), dis(gen)}); - mat = mat * glm::rotate(glm::mat4(1.f), dis(gen), glm::vec3(1.f, 0.f, 0.f)); - mat = mat * glm::scale(glm::mat4(1.f), glm::vec3(scale)); - - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true), mat); - } - - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - - double time_elapse = timer.elapse(); - LOGI(" --> (%f)", time_elapse); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_instances/shaders/frag_shader.frag b/ray_tracing_instances/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_instances/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_instances/shaders/host_device.h b/ray_tracing_instances/shaders/host_device.h deleted file mode 100644 index a22192e..0000000 --- a/ray_tracing_instances/shaders/host_device.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_instances/shaders/passthrough.vert b/ray_tracing_instances/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_instances/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_instances/shaders/post.frag b/ray_tracing_instances/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_instances/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_instances/shaders/raycommon.glsl b/ray_tracing_instances/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing_instances/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing_instances/shaders/raytrace.rchit b/ray_tracing_instances/shaders/raytrace.rchit deleted file mode 100644 index 2eb634e..0000000 --- a/ray_tracing_instances/shaders/raytrace.rchit +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_instances/shaders/raytrace.rgen b/ray_tracing_instances/shaders/raytrace.rgen deleted file mode 100644 index 4802cd0..0000000 --- a/ray_tracing_instances/shaders/raytrace.rgen +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0)); -} diff --git a/ray_tracing_instances/shaders/raytrace.rmiss b/ray_tracing_instances/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_instances/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_instances/shaders/raytraceShadow.rmiss b/ray_tracing_instances/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_instances/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_instances/shaders/vert_shader.vert b/ray_tracing_instances/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_instances/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_instances/shaders/wavefront.glsl b/ray_tracing_instances/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_instances/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_intersection/CMakeLists.txt b/ray_tracing_intersection/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_intersection/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_intersection/README.md b/ray_tracing_intersection/README.md deleted file mode 100644 index 5ca4f09..0000000 --- a/ray_tracing_intersection/README.md +++ /dev/null @@ -1,520 +0,0 @@ -# Intersection Shader - Tutorial - -![](images/intersection.png) -Author: [Martin-Karl Lefrançois](https://devblogs.nvidia.com/author/mlefrancois/) - - -## Tutorial ([Setup](../docs/setup.md)) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -This tutorial chapter shows how to use intersection shader and render different primitives with different materials. - - -## High Level Implementation - -On a high level view, we will - -* Add 2.000.000 axis aligned bounding boxes in a BLAS -* 2 materials will be added -* Every second intersected object will be a sphere or a cube and will use one of the two material. - -To do this, we will need to: - -* Add an intersection shader (.rint) -* Add a new closest hit shader (.chit) -* Create `VkAccelerationStructureGeometryKHR` from `VkAccelerationStructureGeometryAabbsDataKHR` - -## Creating all implicit objects - -In `host_device.h`, we will add the structures we will need. First the structure that defines a sphere. Note that it will also be use for defining the box. This information will be retrieve in the intersection shader to return the intersection point. - -~~~~ C++ -struct Sphere -{ - vec3 center; - float radius; -}; -~~~~ - -Then we need the Aabb structure holding all the spheres, but also used for the creation of the BLAS (`VK_GEOMETRY_TYPE_AABBS_KHR`). - -~~~~ C++ -struct Aabb -{ - vec3 minimum; - vec3 maximum; -}; -~~~~ - -Also add the following define to distinguish between sphere and box - -~~~~ C++ -#define KIND_SPHERE 0 -#define KIND_CUBE 1 -~~~~ - - -All the information will need to be hold in buffers, which will be available to the shaders. - -~~~~ C++ - std::vector m_spheres; // All spheres - nvvkBuffer m_spheresBuffer; // Buffer holding the spheres - nvvkBuffer m_spheresAabbBuffer; // Buffer of all Aabb - nvvkBuffer m_spheresMatColorBuffer; // Multiple materials - nvvkBuffer m_spheresMatIndexBuffer; // Define which sphere uses which material -~~~~ - -Finally, there are two functions, one to create the spheres, and one that will create the intermediate structure for the BLAS, similar to `objectToVkGeometryKHR()`. - -~~~~ C++ - void createSpheres(); - auto sphereToVkGeometryKHR(); -~~~~ - -The following implementation will create 2.000.000 spheres at random positions and radius. It will create the Aabb from the sphere definition, two materials which will be assigned alternatively to each object. All the created information will be moved to Vulkan buffers to be accessed by the intersection and closest shaders. - -~~~~ C++ - -//-------------------------------------------------------------------------------------------------- -// Creating all spheres -// -void HelloVulkan::createSpheres(uint32_t nbSpheres) -{ - std::random_device rd{}; - std::mt19937 gen{rd()}; - std::normal_distribution xzd{0.f, 5.f}; - std::normal_distribution yd{6.f, 3.f}; - std::uniform_real_distribution radd{.05f, .2f}; - - // All spheres - m_spheres.resize(nbSpheres); - for(uint32_t i = 0; i < nbSpheres; i++) - { - Sphere s; - s.center = glm::vec3(xzd(gen), yd(gen), xzd(gen)); - s.radius = radd(gen); - m_spheres[i] = std::move(s); - } - - // Axis aligned bounding box of each sphere - std::vector aabbs; - aabbs.reserve(nbSpheres); - for(const auto& s : m_spheres) - { - Aabb aabb; - aabb.minimum = s.center - glm::vec3(s.radius); - aabb.maximum = s.center + glm::vec3(s.radius); - aabbs.emplace_back(aabb); - } - - // Creating two materials - MaterialObj mat; - mat.diffuse = glm::vec3(0, 1, 1); - std::vector materials; - std::vector matIdx(nbSpheres); - materials.emplace_back(mat); - mat.diffuse = glm::vec3(1, 1, 0); - materials.emplace_back(mat); - - // Assign a material to each sphere - for(size_t i = 0; i < m_spheres.size(); i++) - { - matIdx[i] = i % 2; - } - - // Creating all buffers - using vkBU = VkBufferUsageFlagBits; - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); - m_spheresMatIndexBuffer = - m_alloc.createBuffer(cmdBuf, matIdx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); - m_spheresMatColorBuffer = - m_alloc.createBuffer(cmdBuf, materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); - genCmdBuf.submitAndWait(cmdBuf); - - // Debug information - m_debug.setObjectName(m_spheresBuffer.buffer, "spheres"); - m_debug.setObjectName(m_spheresAabbBuffer.buffer, "spheresAabb"); - m_debug.setObjectName(m_spheresMatColorBuffer.buffer, "spheresMat"); - m_debug.setObjectName(m_spheresMatIndexBuffer.buffer, "spheresMatIdx"); - - // Adding an extra instance to get access to the material buffers - ObjDesc objDesc{}; - objDesc.materialAddress = nvvk::getBufferDeviceAddress(m_device, m_spheresMatColorBuffer.buffer); - objDesc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, m_spheresMatIndexBuffer.buffer); - m_objDesc.emplace_back(objDesc); - - ObjInstance instance{}; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.emplace_back(instance); -} -~~~~ - -Do not forget to destroy the buffers in `destroyResources()` - -~~~~ C++ - m_alloc.destroy(m_spheresBuffer); - m_alloc.destroy(m_spheresAabbBuffer); - m_alloc.destroy(m_spheresMatColorBuffer); - m_alloc.destroy(m_spheresMatIndexBuffer); -~~~~ - -We need a new bottom level acceleration structure (BLAS) to hold the implicit primitives. For efficiency and since all those primitives are static, they will all be added in a single BLAS. - -What is changing compare to triangle primitive is the Aabb data (see Aabb structure) and the geometry type (`VK_GEOMETRY_TYPE_AABBS_KHR`). - -~~~~ C++ -//-------------------------------------------------------------------------------------------------- -// Returning the ray tracing geometry used for the BLAS, containing all spheres -// -auto HelloVulkan::sphereToVkGeometryKHR() -{ - VkDeviceAddress dataAddress = nvvk::getBufferDeviceAddress(m_device, m_spheresAabbBuffer.buffer); - - VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR}; - aabbs.data.deviceAddress = dataAddress; - aabbs.stride = sizeof(Aabb); - - // Setting up the build info of the acceleration (C version, c++ gives wrong type) - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.aabbs = aabbs; - - VkAccelerationStructureBuildRangeInfoKHR offset{}; - offset.firstVertex = 0; - offset.primitiveCount = (uint32_t)m_spheres.size(); // Nb aabb - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - return input; -} -~~~~ - -## Setting Up the Scene - -In `main.cpp`, where we are loading the OBJ model, we can replace it with - -~~~~ C++ - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - helloVk.createSpheres(2000000); -~~~~ - - **:warning: Note:** it is possible to have more OBJ models, but the spheres will need to be added after all of them, due the way we build TLAS. - -The scene will be large, better to move the camera out - -~~~~ C++ - CameraManip.setLookat(glm::vec3(20, 20, 20), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); -~~~~ - -## Acceleration Structures - -### BLAS - -The function `createBottomLevelAS()` is creating a BLAS per OBJ, the following modification will add a new BLAS containing the Aabb's of all spheres. - -~~~~ C++ -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - - // Spheres - { - auto blas = sphereToVkGeometryKHR(); - allBlas.emplace_back(blas); - } - - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} -~~~~ - -### TLAS - -Similarly in `createTopLevelAS()`, the top level acceleration structure will need to add a reference to the BLAS of the spheres. We are setting the instanceCustomId and blasId to the last element, which is why the sphere BLAS must be added after everything else. - -The hitGroupId will be set to 1 instead of 0. We need to add a new hit group for the implicit primitives, since we will need to compute attributes like the normal, since they are not provide like with triangle primitives. - -Because we have added an extra instance when creating the implicit objects, there is one element less to loop for. Therefore the loop will now look like this: - -~~~~ C++ - auto nbObj = static_cast(m_instances.size()) - 1; - tlas.reserve(nbObj); - for(uint32_t i = 0; i < nbObj; i++) - { - const auto& inst = m_instances[i]; - ... - } -~~~~ - - -Just after the loop and before building the TLAS, we need to add the following. - -~~~~ C++ - // Add the blas containing all implicit objects - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(glm::mat4(1)); // Position of the instance (identity) - rayInst.instanceCustomIndex = nbObj; // nbObj == last object == implicit - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(static_cast(m_objModel.size())); - rayInst.instanceShaderBindingTableRecordOffset = 1; // We will use the same hit group for all objects - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - tlas.emplace_back(rayInst); - } -~~~~ - -The `instanceCustomIndex` will give us the last element of `m_instances`, and in the shader will will be able to access the materials -assigned to the implicit objects. - -## Descriptors - -To access the newly created buffers holding all the spheres, some changes are required to the descriptors. - -Add a new enum to `Binding` -~~~~ C++ - eImplicit = 3, // All implicit objects -~~~~ - -The descriptor need to add an binding to the implicit object buffer. - -~~~~ C++ - // Storing spheres (binding = 3) - m_descSetLayoutBind.addBinding(eImplicit, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR); -~~~~ - -The function `updateDescriptorSet()` which is writing the values of the buffer need also to be modified. -Then write the buffer for the spheres after the array of textures - -~~~~ C++ - VkDescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, eImplicit, &dbiSpheres)); -~~~~ - -## Intersection Shader - -The intersection shader is added to the Hit Group `VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR`. In our example, we already have a Hit Group for triangle and a closest hit associated. We will add a new one, which will become the Hit Group ID (1), see the TLAS section. - -Here is how the two hit group looks like: - -~~~~ C++ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eClosestHit2, - eIntersection, - eShaderGroupCount - }; - - // Closest hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit2] = stage; - // Intersection - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR; - stages[eIntersection] = stage; -~~~~ - -~~~~ C++ - // closest hit shader + Intersection (Hit group 2) - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; - group.closestHitShader = eClosestHit2; - group.intersectionShader = eIntersection; - m_rtShaderGroups.push_back(group); -~~~~ - -### raytrace.rint - -The intersection shader `raytrace.rint` need to be added to the shader directory and CMake to be rerun such that it is added to the project. The shader will be called every time a ray will hit one of the Aabb of the scene. Note that there are no Aabb information that can be retrieved in the intersection shader. It is also not possible to have the value of the hit point that the ray tracer might have calculated on the GPU. - -The only information we have is that one of the Aabb was hit and using the `gl_PrimitiveID`, it is possible to know which one it was. Then, with the information stored in the buffer, we can retrive the geometry information of the sphere. - -We first declare the extensions and include common files. - -~~~~ C++ -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" -~~~~ - - -The following is the topology of all spheres, which we will be able to retrieve using `gl_PrimitiveID`. - -~~~~ C++ -layout(binding = 3, set = eImplicit, scalar) buffer allSpheres_ -{ - Sphere allSpheres[]; -}; -~~~~ - -We will implement two intersetion method against the incoming ray. - -~~~~ C++ -struct Ray -{ - vec3 origin; - vec3 direction; -}; -~~~~ - -The sphere intersection - -~~~~ C++ -// Ray-Sphere intersection -// http://viclw17.github.io/2018/07/16/raytracing-ray-sphere-intersection/ -float hitSphere(const Sphere s, const Ray r) -{ - vec3 oc = r.origin - s.center; - float a = dot(r.direction, r.direction); - float b = 2.0 * dot(oc, r.direction); - float c = dot(oc, oc) - s.radius * s.radius; - float discriminant = b * b - 4 * a * c; - if(discriminant < 0) - { - return -1.0; - } - else - { - return (-b - sqrt(discriminant)) / (2.0 * a); - } -} -~~~~ - -And the axis aligned bounding box intersection - -~~~~ C++ -// Ray-AABB intersection -float hitAabb(const Aabb aabb, const Ray r) -{ - vec3 invDir = 1.0 / r.direction; - vec3 tbot = invDir * (aabb.minimum - r.origin); - vec3 ttop = invDir * (aabb.maximum - r.origin); - vec3 tmin = min(ttop, tbot); - vec3 tmax = max(ttop, tbot); - float t0 = max(tmin.x, max(tmin.y, tmin.z)); - float t1 = min(tmax.x, min(tmax.y, tmax.z)); - return t1 > max(t0, 0.0) ? t0 : -1.0; -} -~~~~ - -Both are returning -1 if there is no hit, otherwise, it returns the distance from to origin of the ray. - -Retrieving the ray is straight forward - -~~~~ C++ -void main() -{ - Ray ray; - ray.origin = gl_WorldRayOriginEXT; - ray.direction = gl_WorldRayDirectionEXT; -~~~~ - -And getting the information about the geometry enclosed in the Aabb can be done like this. - -~~~~ C++ - // Sphere data - Sphere sphere = allSpheres.i[gl_PrimitiveID]; -~~~~ - -Now we just need to know if we will hit a sphere or a cube. - -~~~~ C++ - float tHit = -1; - int hitKind = gl_PrimitiveID % 2 == 0 ? KIND_SPHERE : KIND_CUBE; - if(hitKind == KIND_SPHERE) - { - // Sphere intersection - tHit = hitSphere(sphere, ray); - } - else - { - // AABB intersection - Aabb aabb; - aabb.minimum = sphere.center - vec3(sphere.radius); - aabb.maximum = sphere.center + vec3(sphere.radius); - tHit = hitAabb(aabb, ray); - } - ~~~~ - -Intersection information is reported using `reportIntersectionEXT`, with a distance from the origin and a second argument (hitKind) that can be used to differentiate the primitive type. - -~~~~ C++ - - // Report hit point - if(tHit > 0) - reportIntersectionEXT(tHit, hitKind); -} -~~~~ - -The shader can be found [here](shaders/raytrace.rint) - -### raytrace2.rchit - -The new closest hit can be found [here](shaders/raytrace2.rchit) - -This shader is almost identical to original `raytrace.rchit`, but since the primitive is implicit, we will only need to compute the normal for the primitive that was hit. - -We retrieve the world position from the ray and the `gl_HitTEXT` which was set in the intersection shader. - -~~~~ C++ - vec3 worldPos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; -~~~~ - -The sphere information is retrieved the same way as in the `raytrace.rint` shader. - -~~~~ C++ - Sphere instance = allSpheres.i[gl_PrimitiveID]; -~~~~ - -Then we compute the normal, as for a sphere. - -~~~~ C++ - // Computing the normal at hit position - vec3 normal = normalize(worldPos - instance.center); -~~~~ - -To know if we have intersect a cube rather than a sphere, we are using `gl_HitKindEXT`, which was set in the second argument of `reportIntersectionEXT`. - -So when this is a cube, we set the normal to the major axis. - -~~~~ C++ - // Computing the normal for a cube if the hit intersection was reported as 1 - if(gl_HitKindEXT == KIND_CUBE) // Aabb - { - vec3 absN = abs(normal); - float maxC = max(max(absN.x, absN.y), absN.z); - normal = (maxC == absN.x) ? - vec3(sign(normal.x), 0, 0) : - (maxC == absN.y) ? vec3(0, sign(normal.y), 0) : vec3(0, 0, sign(normal.z)); - } -~~~~ diff --git a/ray_tracing_intersection/hello_vulkan.cpp b/ray_tracing_intersection/hello_vulkan.cpp deleted file mode 100644 index cec56e3..0000000 --- a/ray_tracing_intersection/hello_vulkan.cpp +++ /dev/null @@ -1,1094 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" -#include - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Implicit geometries - m_descSetLayoutBind.addBinding(eImplicit, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - VkDescriptorBufferInfo dbiSpheres{m_spheresBuffer.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, eImplicit, &dbiSpheres)); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - m_alloc.destroy(m_rtSBTBuffer); - - m_alloc.destroy(m_spheresBuffer); - m_alloc.destroy(m_spheresAabbBuffer); - m_alloc.destroy(m_spheresMatColorBuffer); - m_alloc.destroy(m_spheresMatIndexBuffer); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - auto nbInst = static_cast(m_instances.size() - 1); // Remove the implicit object - for(uint32_t i = 0; i < nbInst; ++i) - { - auto& inst = m_instances[i]; - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// Returning the ray tracing geometry used for the BLAS, containing all spheres -// -auto HelloVulkan::sphereToVkGeometryKHR() -{ - VkDeviceAddress dataAddress = nvvk::getBufferDeviceAddress(m_device, m_spheresAabbBuffer.buffer); - - VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR}; - aabbs.data.deviceAddress = dataAddress; - aabbs.stride = sizeof(Aabb); - - // Setting up the build info of the acceleration (C version, c++ gives wrong type) - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.aabbs = aabbs; - - VkAccelerationStructureBuildRangeInfoKHR offset{}; - offset.firstVertex = 0; - offset.primitiveCount = (uint32_t)m_spheres.size(); // Nb aabb - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - return input; -} - -//-------------------------------------------------------------------------------------------------- -// Creating all spheres -// -void HelloVulkan::createSpheres(uint32_t nbSpheres) -{ - std::random_device rd{}; - std::mt19937 gen{rd()}; - std::normal_distribution xzd{0.f, 5.f}; - std::normal_distribution yd{6.f, 3.f}; - std::uniform_real_distribution radd{.05f, .2f}; - - // All spheres - m_spheres.resize(nbSpheres); - for(uint32_t i = 0; i < nbSpheres; i++) - { - Sphere s; - s.center = glm::vec3(xzd(gen), yd(gen), xzd(gen)); - s.radius = radd(gen); - m_spheres[i] = std::move(s); - } - - // Axis aligned bounding box of each sphere - std::vector aabbs; - aabbs.reserve(nbSpheres); - for(const auto& s : m_spheres) - { - Aabb aabb; - aabb.minimum = s.center - glm::vec3(s.radius); - aabb.maximum = s.center + glm::vec3(s.radius); - aabbs.emplace_back(aabb); - } - - // Creating two materials - MaterialObj mat; - mat.diffuse = glm::vec3(0, 1, 1); - std::vector materials; - std::vector matIdx(nbSpheres); - materials.emplace_back(mat); - mat.diffuse = glm::vec3(1, 1, 0); - materials.emplace_back(mat); - - // Assign a material to each sphere - for(size_t i = 0; i < m_spheres.size(); i++) - { - matIdx[i] = i % 2; - } - - // Creating all buffers - using vkBU = VkBufferUsageFlagBits; - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - m_spheresBuffer = m_alloc.createBuffer(cmdBuf, m_spheres, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - m_spheresAabbBuffer = m_alloc.createBuffer(cmdBuf, aabbs, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); - m_spheresMatIndexBuffer = - m_alloc.createBuffer(cmdBuf, matIdx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); - m_spheresMatColorBuffer = - m_alloc.createBuffer(cmdBuf, materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); - genCmdBuf.submitAndWait(cmdBuf); - - // Debug information - m_debug.setObjectName(m_spheresBuffer.buffer, "spheres"); - m_debug.setObjectName(m_spheresAabbBuffer.buffer, "spheresAabb"); - m_debug.setObjectName(m_spheresMatColorBuffer.buffer, "spheresMat"); - m_debug.setObjectName(m_spheresMatIndexBuffer.buffer, "spheresMatIdx"); - - - // Adding an extra instance to get access to the material buffers - ObjDesc objDesc{}; - objDesc.materialAddress = nvvk::getBufferDeviceAddress(m_device, m_spheresMatColorBuffer.buffer); - objDesc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, m_spheresMatIndexBuffer.buffer); - m_objDesc.emplace_back(objDesc); - - ObjInstance instance{}; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.emplace_back(instance); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - - // Spheres - { - auto blas = sphereToVkGeometryKHR(); - allBlas.emplace_back(blas); - } - - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - - auto nbObj = static_cast(m_instances.size()) - 1; - tlas.reserve(nbObj); - for(uint32_t i = 0; i < nbObj; i++) - { - const auto& inst = m_instances[i]; - - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - - // Add the blas containing all implicit objects - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(glm::mat4(1)); // (identity) - rayInst.instanceCustomIndex = nbObj; // nbObj == last object == implicit - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(static_cast(m_objModel.size())); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 1; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eClosestHit2, - eIntersection, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - // Closest hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit2] = stage; - // Intersection - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR; - stages[eIntersection] = stage; - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - - // closest hit shader + Intersection - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; - group.closestHitShader = eClosestHit2; - group.intersectionShader = eIntersection; - m_rtShaderGroups.push_back(group); - - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// The Shader Binding Table (SBT) -// - getting all shader handles and write them in a SBT buffer -// - Besides exception, this could be always done like this -// -void HelloVulkan::createRtShaderBindingTable() -{ - uint32_t missCount{2}; - uint32_t hitCount{2}; - auto handleCount = 1 + missCount + hitCount; - uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - - // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. - uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); - - m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member - m_missRegion.stride = handleSizeAligned; - m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_hitRegion.stride = handleSizeAligned; - m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - - // Get the shader group handles - uint32_t dataSize = handleCount * handleSize; - std::vector handles(dataSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); - assert(result == VK_SUCCESS); - - // Allocate a buffer for storing the SBT. - VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. - - // Find the SBT addresses of each group - VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; - VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - m_rgenRegion.deviceAddress = sbtAddress; - m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; - m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; - - // Helper to retrieve the handle data - auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; - - // Map the SBT buffer and write in the handles. - auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); - uint8_t* pData{nullptr}; - uint32_t handleIdx{0}; - // Raygen - pData = pSBTBuffer; - memcpy(pData, getHandle(handleIdx++), handleSize); - // Miss - pData = pSBTBuffer + m_rgenRegion.size; - for(uint32_t c = 0; c < missCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_missRegion.stride; - } - // Hit - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; - for(uint32_t c = 0; c < hitCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_hitRegion.stride; - } - - m_alloc.unmap(m_rtSBTBuffer); - m_alloc.finalizeAndReleaseStaging(); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); - - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing_intersection/hello_vulkan.h b/ray_tracing_intersection/hello_vulkan.h deleted file mode 100644 index da17d01..0000000 --- a/ray_tracing_intersection/hello_vulkan.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 55.f, 8.f}, // light position - 0, // instance Id - 1000.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - - nvvk::Buffer m_rtSBTBuffer; - VkStridedDeviceAddressRegionKHR m_rgenRegion{}; - VkStridedDeviceAddressRegionKHR m_missRegion{}; - VkStridedDeviceAddressRegionKHR m_hitRegion{}; - VkStridedDeviceAddressRegionKHR m_callRegion{}; - - // Push constant for ray tracer - PushConstantRay m_pcRay{}; - - - std::vector m_spheres; // All spheres - nvvk::Buffer m_spheresBuffer; // Buffer holding the spheres - nvvk::Buffer m_spheresAabbBuffer; // Buffer of all Aabb - nvvk::Buffer m_spheresMatColorBuffer; // Multiple materials - nvvk::Buffer m_spheresMatIndexBuffer; // Define which sphere uses which material - - void createSpheres(uint32_t nbSpheres); - auto sphereToVkGeometryKHR(); -}; diff --git a/ray_tracing_intersection/images/intersection.png b/ray_tracing_intersection/images/intersection.png deleted file mode 100644 index d146e25..0000000 Binary files a/ray_tracing_intersection/images/intersection.png and /dev/null differ diff --git a/ray_tracing_intersection/main.cpp b/ray_tracing_intersection/main.cpp deleted file mode 100644 index 3182ae2..0000000 --- a/ray_tracing_intersection/main.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } - ImGui::Text("Nb Spheres and Cubes: %lu", helloVk.m_spheres.size()); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(20, 20, 20), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - contextInfo.addDeviceExtension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME); - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - // helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - helloVk.createSpheres(2000000); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - helloVk.createRtShaderBindingTable(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_intersection/shaders/frag_shader.frag b/ray_tracing_intersection/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_intersection/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_intersection/shaders/host_device.h b/ray_tracing_intersection/shaders/host_device.h deleted file mode 100644 index 03ae314..0000000 --- a/ray_tracing_intersection/shaders/host_device.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2, // Access to textures - eImplicit = 3 // All implicit objects -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - -struct Sphere -{ - vec3 center; - float radius; -}; - -struct Aabb -{ - vec3 minimum; - vec3 maximum; -}; - -#define KIND_SPHERE 0 -#define KIND_CUBE 1 - -#endif diff --git a/ray_tracing_intersection/shaders/passthrough.vert b/ray_tracing_intersection/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_intersection/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_intersection/shaders/post.frag b/ray_tracing_intersection/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_intersection/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_intersection/shaders/raycommon.glsl b/ray_tracing_intersection/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing_intersection/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing_intersection/shaders/raytrace.rchit b/ray_tracing_intersection/shaders/raytrace.rchit deleted file mode 100644 index c79911d..0000000 --- a/ray_tracing_intersection/shaders/raytrace.rchit +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_intersection/shaders/raytrace.rgen b/ray_tracing_intersection/shaders/raytrace.rgen deleted file mode 100644 index 4802cd0..0000000 --- a/ray_tracing_intersection/shaders/raytrace.rgen +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0)); -} diff --git a/ray_tracing_intersection/shaders/raytrace.rint b/ray_tracing_intersection/shaders/raytrace.rint deleted file mode 100644 index b772c46..0000000 --- a/ray_tracing_intersection/shaders/raytrace.rint +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require -#include "raycommon.glsl" -#include "wavefront.glsl" - - -layout(set = 1, binding = eImplicit, scalar) buffer allSpheres_ -{ - Sphere allSpheres[]; -}; - - -struct Ray -{ - vec3 origin; - vec3 direction; -}; - -// Ray-Sphere intersection -// http://viclw17.github.io/2018/07/16/raytracing-ray-sphere-intersection/ -float hitSphere(const Sphere s, const Ray r) -{ - vec3 oc = r.origin - s.center; - float a = dot(r.direction, r.direction); - float b = 2.0 * dot(oc, r.direction); - float c = dot(oc, oc) - s.radius * s.radius; - float discriminant = b * b - 4 * a * c; - if(discriminant < 0) - { - return -1.0; - } - else - { - return (-b - sqrt(discriminant)) / (2.0 * a); - } -} - -// Ray-AABB intersection -float hitAabb(const Aabb aabb, const Ray r) -{ - vec3 invDir = 1.0 / r.direction; - vec3 tbot = invDir * (aabb.minimum - r.origin); - vec3 ttop = invDir * (aabb.maximum - r.origin); - vec3 tmin = min(ttop, tbot); - vec3 tmax = max(ttop, tbot); - float t0 = max(tmin.x, max(tmin.y, tmin.z)); - float t1 = min(tmax.x, min(tmax.y, tmax.z)); - return t1 > max(t0, 0.0) ? t0 : -1.0; -} - -void main() -{ - Ray ray; - ray.origin = gl_WorldRayOriginEXT; - ray.direction = gl_WorldRayDirectionEXT; - - // Sphere data - Sphere sphere = allSpheres[gl_PrimitiveID]; - - float tHit = -1; - int hitKind = gl_PrimitiveID % 2 == 0 ? KIND_SPHERE : KIND_CUBE; - if(hitKind == KIND_SPHERE) - { - // Sphere intersection - tHit = hitSphere(sphere, ray); - } - else - { - // AABB intersection - Aabb aabb; - aabb.minimum = sphere.center - vec3(sphere.radius); - aabb.maximum = sphere.center + vec3(sphere.radius); - tHit = hitAabb(aabb, ray); - } - - // Report hit point - if(tHit > 0) - reportIntersectionEXT(tHit, hitKind); -} diff --git a/ray_tracing_intersection/shaders/raytrace.rmiss b/ray_tracing_intersection/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_intersection/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_intersection/shaders/raytrace2.rchit b/ray_tracing_intersection/shaders/raytrace2.rchit deleted file mode 100644 index 693e00d..0000000 --- a/ray_tracing_intersection/shaders/raytrace2.rchit +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; -layout(set = 1, binding = eImplicit, scalar) buffer allSpheres_ {Sphere i[];} allSpheres; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - vec3 worldPos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - - Sphere instance = allSpheres.i[gl_PrimitiveID]; - - // Computing the normal at hit position - vec3 worldNrm = normalize(worldPos - instance.center); - - // Computing the normal for a cube - if(gl_HitKindEXT == KIND_CUBE) // Aabb - { - vec3 absN = abs(worldNrm); - float maxC = max(max(absN.x, absN.y), absN.z); - worldNrm = (maxC == absN.x) ? vec3(sign(worldNrm.x), 0, 0) : - (maxC == absN.y) ? vec3(0, sign(worldNrm.y), 0) : - vec3(0, 0, sign(worldNrm.z)); - } - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - vec3 specular = vec3(0); - float attenuation = 0.3; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - attenuation = 1; - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_intersection/shaders/raytraceShadow.rmiss b/ray_tracing_intersection/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_intersection/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_intersection/shaders/vert_shader.vert b/ray_tracing_intersection/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_intersection/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_intersection/shaders/wavefront.glsl b/ray_tracing_intersection/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_intersection/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_jitter_cam/CMakeLists.txt b/ray_tracing_jitter_cam/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_jitter_cam/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_jitter_cam/README.md b/ray_tracing_jitter_cam/README.md deleted file mode 100644 index 44340ab..0000000 --- a/ray_tracing_jitter_cam/README.md +++ /dev/null @@ -1,271 +0,0 @@ -# Jitter Camera - Tutorial - -![](images/antialiasing.png) - -## Tutorial ([Setup](../docs/setup.md)) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - - -In this extension, we will implement antialiasing by jittering the offset of each ray for each pixel over time, instead of always shooting each ray from the middle of its pixel. - -## Random Functions - -We will use some simple functions for random number generation, which suffice for this example. - -Create a new shader file `random.glsl` with the following code. Add it to the `shaders` directory and rerun CMake, and include this new file in `raytrace.rgen`: - -~~~~ C++ -// Generate a random unsigned int from two unsigned int values, using 16 pairs -// of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis, -// "GPU Random Numbers via the Tiny Encryption Algorithm" -uint tea(uint val0, uint val1) -{ - uint v0 = val0; - uint v1 = val1; - uint s0 = 0; - - for(uint n = 0; n < 16; n++) - { - s0 += 0x9e3779b9; - v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); - v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); - } - - return v0; -} - -// Generate a random unsigned int in [0, 2^24) given the previous RNG state -// using the Numerical Recipes linear congruential generator -uint lcg(inout uint prev) -{ - uint LCG_A = 1664525u; - uint LCG_C = 1013904223u; - prev = (LCG_A * prev + LCG_C); - return prev & 0x00FFFFFF; -} - -// Generate a random float in [0, 1) given the previous RNG state -float rnd(inout uint prev) -{ - return (float(lcg(prev)) / float(0x01000000)); -} -~~~~ - -## Frame Number - -Since our jittered samples will be accumulated across frames, we need to know which frame we are currently rendering. A frame number of 0 will indicate a new frame, and we will accumulate the data for larger frame numbers. - -Note that the uniform image is read/write, which makes it possible to accumulate previous frames. - -Add the frame member to the `PushConstantRay` struct in `shaders/host_device.h`: - -~~~~ C++ -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; - int frame; -}; -~~~~ - -## Random and Jitter - -In `raytrace.rgen`, at the beginning of `main()`, initialize the random seed: - -~~~~ C++ - // Initialize the random number - uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame); -~~~~ - -Then we need two random numbers to vary the X and Y inside the pixel, except for frame 0, where we always shoot -in the center. - -~~~~ C++ -float r1 = rnd(seed); -float r2 = rnd(seed); -// Subpixel jitter: send the ray through a different position inside the pixel -// each time, to provide antialiasing. -vec2 subpixel_jitter = pcRay.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2); -~~~~ - -Now we only need to change how we compute the pixel center: - -~~~~ C++ -const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter; -~~~~ - -## Storing or Updating - -At the end of `main()`, if the frame number is equal to 0, we write directly to the image. -Otherwise, we combine the new image with the previous `frame` frames. - -~~~~ C++ - // Do accumulation over time - if(pcRay.frame > 0) - { - float a = 1.0f / float(pcRay.frame + 1); - vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz; - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f)); - } - else - { - // First frame, replace the value in the buffer - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.f)); - } -~~~~ - -## Application Frame Update - -We need to increment the current rendering frame, but we also need to reset it when something in the -scene is changing. - -Add two new functions to the `HelloVulkan` class: - -~~~~ C++ - void resetFrame(); - void updateFrame(); -~~~~ - -The implementation of `updateFrame` resets the frame counter if the camera has changed; otherwise, it increments the frame counter. - -~~~~ C++ -//-------------------------------------------------------------------------------------------------- -// If the camera matrix or the the fov has changed, resets the frame. -// otherwise, increments frame. -// -void HelloVulkan::updateFrame() -{ - static glm::mat4 refCamMatrix; - static float refFov{CameraManip.getFov()}; - - const auto& m = CameraManip.getMatrix(); - const auto fov = CameraManip.getFov(); - - if(refCamMatrix != m || refFov != fov) - { - resetFrame(); - refCamMatrix = m; - refFov = fov; - } - m_pcRay.frame++; -} -~~~~ - -Since `resetFrame` will be called before `updateFrame` increments the frame counter, `resetFrame` will set the frame counter to -1: - -~~~~ C++ -void HelloVulkan::resetFrame() -{ - m_pcRay.frame = -1; -} -~~~~ - -At the begining of `HelloVulkan::raytrace`, call - -~~~~ C++ - updateFrame(); -~~~~ - -The application will now antialias the image when ray tracing is enabled. - -Adding `resetFrame()` in `HelloVulkan::onResize()` will also take care of clearing the buffer while resizing the window. - - - -## Resetting Frame on UI Change - -The frame number should also be reset when any parts of the scene change, such as the light direction or the background color. In `renderUI()` in `main.cpp`, check for UI changes and reset the frame number when they happen: - -~~~~ C++ -void renderUI(HelloVulkan& helloVk) -{ - bool changed = false; - - changed |= ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - auto& pc = helloVk.m_pushConstant; - changed |= ImGui::RadioButton("Point", &pc.lightType, 0); - ImGui::SameLine(); - 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) - helloVk.resetFrame(); -} -~~~~ - -We also need to check for UI changes inside the main loop inside `main()`: - -~~~~ C++ - bool changed = false; - // Edit 3 floats representing a color - changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - // Switch between raster and ray tracing - changed |= ImGui::Checkbox("Ray Tracer mode", &useRaytracer); - if(changed) - helloVk.resetFrame(); -~~~~ - -## Quality - -After enough samples, the quality of the rendering will be sufficiently high that it might make sense to avoid accumulating further images. - -Add a member variable to `HelloVulkan` - -~~~~ C++ -int m_maxFrames{100}; -~~~~ - -and also add a way to control it in `renderUI()`, making sure that `m_maxFrames` cannot be set below 1: - -~~~~ C++ -changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 100); -~~~~ - -Then in `raytrace()`, immediately after the call to `updateFrame()`, return if the current frame has exceeded the max frame. - -~~~~ C++ - if(m_pcRay.frame >= m_maxFrames) - return; -~~~~ - -Since the output image won't be modified by the ray tracer, we will simply display the last good image, reducing GPU usage when the target quality has been reached. - -## More Samples in RayGen - -To improve efficiency, we can perform multiple samples directly in the ray generation shader. This will be faster than calling `raytrace()` the equivalent number of times. - -To do this, add a constant to `raytrace.rgen` (this could alternatively be added to the push constant block and controlled by the application): - -~~~~ C++ -const int NBSAMPLES = 10; -~~~~ - -In `main()`, after initializing the random number seed, create a loop that encloses the lines from the generation of `r1` and `r2` to the `traceRayEXT` call, and accumulates the colors returned by `traceRayEXT`. At the end of the loop, divide by the number of samples that were taken. - -~~~~ C++ - vec3 hitValues = vec3(0); - - for(int smpl = 0; smpl < NBSAMPLES; smpl++) - { - float r1 = rnd(seed); - float r2 = rnd(seed); - // ... - // TraceRayEXT( ... ); - hitValues += prd.hitValue; - } - prd.hitValue = hitValues / NBSAMPLES; -~~~~ - -For a given value of `m_maxFrames` and `NBSAMPLE`, the image will have `m_maxFrames * NBSAMPLE` antialiasing samples. - -For instance, if `m_maxFrames = 10` and `NBSAMPLE = 10`, this will be equivalent in quality to an image using `m_maxFrames = 100` and `NBSAMPLE = 1`. - -However, using `NBSAMPLE=10` in the ray generation shader will be faster than calling `raytrace()` with `NBSAMPLE=1` 10 times in a row. diff --git a/ray_tracing_jitter_cam/hello_vulkan.cpp b/ray_tracing_jitter_cam/hello_vulkan.cpp deleted file mode 100644 index 4f206552..0000000 --- a/ray_tracing_jitter_cam/hello_vulkan.cpp +++ /dev/null @@ -1,971 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - m_alloc.destroy(m_rtSBTBuffer); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); - resetFrame(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - - // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. - if(m_rtProperties.maxRayRecursionDepth <= 1) - { - throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); - } - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// The Shader Binding Table (SBT) -// - getting all shader handles and write them in a SBT buffer -// - Besides exception, this could be always done like this -// -void HelloVulkan::createRtShaderBindingTable() -{ - uint32_t missCount{2}; - uint32_t hitCount{1}; - auto handleCount = 1 + missCount + hitCount; - uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - - // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. - uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); - - m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member - m_missRegion.stride = handleSizeAligned; - m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_hitRegion.stride = handleSizeAligned; - m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - - // Get the shader group handles - uint32_t dataSize = handleCount * handleSize; - std::vector handles(dataSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); - assert(result == VK_SUCCESS); - - // Allocate a buffer for storing the SBT. - VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. - - // Find the SBT addresses of each group - VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; - VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - m_rgenRegion.deviceAddress = sbtAddress; - m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; - m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; - - // Helper to retrieve the handle data - auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; - - // Map the SBT buffer and write in the handles. - auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); - uint8_t* pData{nullptr}; - uint32_t handleIdx{0}; - // Raygen - pData = pSBTBuffer; - memcpy(pData, getHandle(handleIdx++), handleSize); - // Miss - pData = pSBTBuffer + m_rgenRegion.size; - for(uint32_t c = 0; c < missCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_missRegion.stride; - } - // Hit - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; - for(uint32_t c = 0; c < hitCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_hitRegion.stride; - } - - m_alloc.unmap(m_rtSBTBuffer); - m_alloc.finalizeAndReleaseStaging(); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - updateFrame(); - if(m_pcRay.frame >= m_maxFrames) - return; - - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); - - - m_debug.endLabel(cmdBuf); -} - - -//-------------------------------------------------------------------------------------------------- -// If the camera matrix or the the fov has changed, resets the frame. -// otherwise, increments frame. -// -void HelloVulkan::updateFrame() -{ - static glm::mat4 refCamMatrix; - static float refFov{CameraManip.getFov()}; - - const auto& m = CameraManip.getMatrix(); - const auto fov = CameraManip.getFov(); - - if(refCamMatrix != m || refFov != fov) - { - resetFrame(); - refCamMatrix = m; - refFov = fov; - } - m_pcRay.frame++; -} - -void HelloVulkan::resetFrame() -{ - m_pcRay.frame = -1; -} diff --git a/ray_tracing_jitter_cam/hello_vulkan.h b/ray_tracing_jitter_cam/hello_vulkan.h deleted file mode 100644 index 4612525..0000000 --- a/ray_tracing_jitter_cam/hello_vulkan.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - void resetFrame(); - void updateFrame(); - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - - nvvk::Buffer m_rtSBTBuffer; - VkStridedDeviceAddressRegionKHR m_rgenRegion{}; - VkStridedDeviceAddressRegionKHR m_missRegion{}; - VkStridedDeviceAddressRegionKHR m_hitRegion{}; - VkStridedDeviceAddressRegionKHR m_callRegion{}; - - int m_maxFrames{10}; - - // Push constant for ray tracer - PushConstantRay m_pcRay{}; -}; diff --git a/ray_tracing_jitter_cam/images/antialiasing.png b/ray_tracing_jitter_cam/images/antialiasing.png deleted file mode 100644 index 09b599b..0000000 Binary files a/ray_tracing_jitter_cam/images/antialiasing.png and /dev/null differ diff --git a/ray_tracing_jitter_cam/main.cpp b/ray_tracing_jitter_cam/main.cpp deleted file mode 100644 index 78b736c..0000000 --- a/ray_tracing_jitter_cam/main.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - bool changed{false}; - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - auto& pc = helloVk.m_pcRaster; - changed |= ImGui::RadioButton("Point", &pc.lightType, 0); - ImGui::SameLine(); - 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); - } - - - changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 100); - if(changed) - helloVk.resetFrame(); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(4, 4, 4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - helloVk.createRtShaderBindingTable(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - bool changed = false; - // Edit 3 floats representing a color - changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - // Switch between raster and ray tracing - changed |= ImGui::Checkbox("Ray Tracer mode", &useRaytracer); - if(changed) - helloVk.resetFrame(); - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_jitter_cam/shaders/frag_shader.frag b/ray_tracing_jitter_cam/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_jitter_cam/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_jitter_cam/shaders/host_device.h b/ray_tracing_jitter_cam/shaders/host_device.h deleted file mode 100644 index bf0ed9e..0000000 --- a/ray_tracing_jitter_cam/shaders/host_device.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; - int frame; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_jitter_cam/shaders/passthrough.vert b/ray_tracing_jitter_cam/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_jitter_cam/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_jitter_cam/shaders/post.frag b/ray_tracing_jitter_cam/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_jitter_cam/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_jitter_cam/shaders/random.glsl b/ray_tracing_jitter_cam/shaders/random.glsl deleted file mode 100644 index ef41f54..0000000 --- a/ray_tracing_jitter_cam/shaders/random.glsl +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -// Generate a random unsigned int from two unsigned int values, using 16 pairs -// of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis, -// "GPU Random Numbers via the Tiny Encryption Algorithm" -uint tea(uint val0, uint val1) -{ - uint v0 = val0; - uint v1 = val1; - uint s0 = 0; - - for(uint n = 0; n < 16; n++) - { - s0 += 0x9e3779b9; - v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); - v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); - } - - return v0; -} - -// Generate a random unsigned int in [0, 2^24) given the previous RNG state -// using the Numerical Recipes linear congruential generator -uint lcg(inout uint prev) -{ - uint LCG_A = 1664525u; - uint LCG_C = 1013904223u; - prev = (LCG_A * prev + LCG_C); - return prev & 0x00FFFFFF; -} - -// Generate a random float in [0, 1) given the previous RNG state -float rnd(inout uint prev) -{ - return (float(lcg(prev)) / float(0x01000000)); -} diff --git a/ray_tracing_jitter_cam/shaders/raycommon.glsl b/ray_tracing_jitter_cam/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing_jitter_cam/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing_jitter_cam/shaders/raytrace.rchit b/ray_tracing_jitter_cam/shaders/raytrace.rchit deleted file mode 100644 index 2eb634e..0000000 --- a/ray_tracing_jitter_cam/shaders/raytrace.rchit +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_jitter_cam/shaders/raytrace.rgen b/ray_tracing_jitter_cam/shaders/raytrace.rgen deleted file mode 100644 index a816f35..0000000 --- a/ray_tracing_jitter_cam/shaders/raytrace.rgen +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#include "random.glsl" -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - -const int NBSAMPLES = 10; - -void main() -{ - // Initialize the random number - uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame); - - vec3 hitValues = vec3(0); - - for(int smpl = 0; smpl < NBSAMPLES; smpl++) - { - - float r1 = rnd(seed); - float r2 = rnd(seed); - // Subpixel jitter: send the ray through a different position inside the pixel - // each time, to provide antialiasing. - vec2 subpixel_jitter = pcRay.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2); - - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter; - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - hitValues += prd.hitValue; - } - prd.hitValue = hitValues / NBSAMPLES; - - // Do accumulation over time - if(pcRay.frame > 0) - { - float a = 1.0f / float(pcRay.frame + 1); - vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz; - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f)); - } - else - { - // First frame, replace the value in the buffer - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.f)); - } -} diff --git a/ray_tracing_jitter_cam/shaders/raytrace.rmiss b/ray_tracing_jitter_cam/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_jitter_cam/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_jitter_cam/shaders/raytraceShadow.rmiss b/ray_tracing_jitter_cam/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_jitter_cam/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_jitter_cam/shaders/vert_shader.vert b/ray_tracing_jitter_cam/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_jitter_cam/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_jitter_cam/shaders/wavefront.glsl b/ray_tracing_jitter_cam/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_jitter_cam/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_manyhits/CMakeLists.txt b/ray_tracing_manyhits/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_manyhits/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_manyhits/README.md b/ray_tracing_manyhits/README.md deleted file mode 100644 index 417f03e..0000000 --- a/ray_tracing_manyhits/README.md +++ /dev/null @@ -1,280 +0,0 @@ -# Multiple Closest Hit Shaders - Tutorial - -![](images/manyhits.png) - -## Tutorial ([Setup](../docs/setup.md)) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -The ray tracing tutorial only uses one closest hit shader, but it is also possible to have multiple closest hit shaders. -For example, this could be used to give different models different shaders, or to use a less complex shader when tracing -reflections. - -## Setting up the Scene - -For this example, we will load the `wuson` model and create another translated instance of it. - -Then you can change the `helloVk.loadModel` calls to the following: - -~~~~ C++ - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), - glm::translate(glm::mat4(1),glm::vec3(-1, 0, 0))); - - helloVk.m_instances.push_back({glm::translate(glm::mat4(1),glm::vec3(1, 0, 0)), 0}); // Adding an instance of the Wuson - - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); -~~~~ - -## Adding a new Closest Hit Shader - -We will need to create a new closest hit shader (CHIT), to add it to the raytracing pipeline, and to indicate which instance will use this shader. - -### `raytrace2.rchit` - -We can make a very simple shader to differentiate this closest hit shader from the other one. -As an example, create a new file called `raytrace2.rchit`, and add it to Visual Studio's `shaders` filter with the other shaders. - -~~~~ C++ -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable - -#include "raycommon.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -void main() -{ - prd.hitValue = vec3(1,0,0); -} -~~~~ - -### `createRtPipeline` - -This new shader needs to be added to the raytracing pipeline. So, in `createRtPipeline` in `hello_vulkan.cpp`, load the new closest hit shader immediately after loading the first one. - -~~~~ C++ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eClosestHit2, - eShaderGroupCount - }; - - // ... - - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit2] = stage; -~~~~ - -Then add a new hit group group immediately after adding the first hit group: - -~~~~ C++ - // Hit 2 - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit2; - m_rtShaderGroups.push_back(group); -~~~~ - -### `raytrace.rgen` - -As a test, you can try changing the `sbtRecordOffset` parameter of the `traceRayEXT` call in `raytrace.rgen`. -If you set the offset to `1`, then all ray hits will use the new CHIT, and the raytraced output should look like the image below: - -![](images/manyhits2.png) - -**:warning:** After testing this out, make sure to revert this change in `raytrace.rgen` before continuing. - -### `hello_vulkan.h` - -In the `ObjInstance` structure, we will add a new member `hitgroup` variable that specifies which hit shader the instance will use: - -~~~~ C++ - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - int hitgroup{0}; // Hit group of the instance - }; -~~~~ - -### `hello_vulkan.cpp` - -Finally, we need to tell the top-level acceleration structure which hit group to use for each instance. In `createTopLevelAS()` -in `hello_vulkan.cpp`, we will offset the record of the shading binding table (SBT) with the hit group. - -~~~~ C++ -rayInst.instanceShaderBindingTableRecordOffset = inst.hitgroup; // Using the hit group set in main -~~~~ - -### Choosing the Hit shader - -Back in `main.cpp`, after loading the scene's models, we can now have both `wuson` models use the new CHIT by adding the following: - -~~~~ C++ - helloVk.m_instances[0].hitgroup = 1; - helloVk.m_instances[1].hitgroup = 1; -~~~~ - -![](images/manyhits3.png) - -## Shader Record Data `shaderRecordKHR` - -When creating the [Shader Binding Table](https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap33.html#shader-binding-table), see previous, each entry in the table consists of a handle referring to the shader that it invokes. We have packed all data to the size of `shaderGroupHandleSize`, but each entry could be made larger, to store data that can later be referenced by a `shaderRecordKHR` block in the shader. - -This information can be used to pass extra information to a shader, for each entry in the SBT. - - **:warning: 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. - -The following diagram represents our current SBT, with some data added to `HitGroup1`. As mentioned in the **note**, even though `HitGroup0` has no shader record data, it still needs to be the same size as `HitGroup1`, the largest of the hit group and aligned to the Handle alignment. - -![](images/sbt_0.png) - - -## `hello_vulkan.h` - -In the HelloVulkan class, we will add a structure to hold the hit group data. - -~~~~ C++ - struct HitRecordBuffer - { - glm::vec4 color; - }; - std::vector m_hitShaderRecord; -~~~~ - -### `raytrace2.rchit` - -In the closest hit shader, we can retrieve the shader record using the `layout(shaderRecordEXT)` descriptor - -~~~~ C++ -layout(shaderRecordEXT) buffer sr_ { vec4 shaderRec; }; -~~~~ - -and use this information to return the color: - -~~~~ C++ -void main() -{ - prd.hitValue = shaderRec.rgb; -} -~~~~ - - **:warning: Note:** - Adding a new shader requires to rerun CMake to added to the project compilation system. - -### `main.cpp` - -In `main`, after we set which hit group an instance will use, we can add the data we want to set through the shader record. - -~~~~ C++ - helloVk.m_hitShaderRecord.resize(1); - helloVk.m_hitShaderRecord[0].color = glm::vec4(1, 1, 0, 0); // Yellow -~~~~ - -### `HelloVulkan::createRtShaderBindingTable` - -**:star:NEW:star:** - -The creation of the shading binding table as it was done, was using hardcoded offsets and potentially could lead to errors. -Instead, the new code uses the `nvvk::SBTWraper` that uses the ray tracing pipeline and the `VkRayTracingPipelineCreateInfoKHR` to -create the SBT information. - -The wrapper will find the handles for each group and will add the -data `m_hitShaderRecord` to the Hit group. - -```` C - // Find handle indices and add data - m_sbtWrapper.addIndices(rayPipelineInfo); - m_sbtWrapper.addData(SBTWrapper::eHit, 1, m_hitShaderRecord[0]); - m_sbtWrapper.create(m_rtPipeline); -```` - -The wrapper will make sure the stride covers the largest data and is aligned -based on the GPU properties. - -**OLD - for reference** - -~~Since we are no longer compacting all handles in a continuous buffer, we need to fill the SBT as described above.~~ - -~~~~ C++ - m_hitRegion.stride = nvh::align_up(handleSize + sizeof(HitRecordBuffer), m_rtProperties.shaderGroupHandleAlignment); -~~~~ - -~~Then write the new SBT like this, where only Hit 1 has extra data.~~ - -~~~~ C++ - // Hit - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; - memcpy(pData, getHandle(handleIdx++), handleSize); - - // hit 1 - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size + m_hitRegion.stride; - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += handleSize; - memcpy(pData, &m_hitShaderRecord[0], sizeof(HitRecordBuffer)); // Hit 1 data -~~~~ - -## Ray Trace - -The result should now show both `wuson` models with a yellow color.~~ - -![](images/manyhits4.png) - -## Extending Hit - -The SBT can be larger than the number of shading models, which could then be used to have one shader per instance with its own data. For some applications, instead of retrieving the material information as in the main tutorial using a storage buffer and indexing into it using the `gl_InstanceCustomIndexEXT`, it is possible to set all of the material information in the SBT. - -The following modification will add another entry to the SBT with a different color per instance. The new SBT hit group (2) will use the same CHIT handle (4) as hit group 1. - -![](images/sbt_1.png) - - -### `main.cpp` - -In the description of the scene in `main`, we will tell the `wuson` models to use hit groups 1 and 2 respectively, and to have different colors. - -~~~~ C++ - // Hit shader record info - helloVk.m_hitShaderRecord.resize(2); - helloVk.m_hitShaderRecord[0].color = glm::vec4(0, 1, 0, 0); // Green - helloVk.m_hitShaderRecord[1].color = glm::vec4(0, 1, 1, 0); // Cyan - helloVk.m_instances[0].hitgroup = 1; // wuson 0 - helloVk.m_instances[1].hitgroup = 2; // wuson 1 -~~~~ - -### `createRtShaderBindingTable` - -**:star:NEW:star:** - -If you are using the SBT wrapper, make sure to add the data to the third Hit (2). - -~~~~ C - // Find handle indices and add data - m_sbtWrapper.addIndices(rayPipelineInfo); - m_sbtWrapper.addData(nvvk::SBTWrapper::eHit, 1, m_hitShaderRecord[0]); - m_sbtWrapper.addData(nvvk::SBTWrapper::eHit, 2, m_hitShaderRecord[1]); - m_sbtWrapper.create(m_rtPipeline); -~~~~ - -**OLD** - -~~~~ C++ - // hit 2 - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size + (2 * m_hitRegion.stride); - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += handleSize; - memcpy(pData, &m_hitShaderRecord[1], sizeof(HitRecordBuffer)); // Hit 2 data -~~~~ - -~~**Note:** - 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, - and size per group in a SBT utility to handle this automatically.~~ diff --git a/ray_tracing_manyhits/hello_vulkan.cpp b/ray_tracing_manyhits/hello_vulkan.cpp deleted file mode 100644 index 76d81fb..0000000 --- a/ray_tracing_manyhits/hello_vulkan.cpp +++ /dev/null @@ -1,986 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay -#ifdef USE_SBT_WRAPPER - m_sbtWrapper.destroy(); -#else - m_alloc.destroy(m_rtSBTBuffer); -#endif - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); - -#ifdef USE_SBT_WRAPPER - m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); -#endif -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = inst.hitgroup; // Using the hit group set in main - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eClosestHit2, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - // - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit2] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - // Hit 0 - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - // Hit 1 - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit2; - m_rtShaderGroups.push_back(group); - // Hit 2 - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit2; - m_rtShaderGroups.push_back(group); - - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - -#ifdef USE_SBT_WRAPPER - // Find handle indices and add data - m_sbtWrapper.addIndices(rayPipelineInfo); - m_sbtWrapper.addData(nvvk::SBTWrapper::eHit, 1, m_hitShaderRecord[0]); - m_sbtWrapper.addData(nvvk::SBTWrapper::eHit, 2, m_hitShaderRecord[1]); - m_sbtWrapper.create(m_rtPipeline); -#else - createRtShaderBindingTable(); -#endif - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// The Shader Binding Table (SBT) -// - getting all shader handles and write them in a SBT buffer -// - Besides exception, this could be always done like this -// See how the SBT buffer is used in run() -// -#ifndef USE_SBT_WRAPPER -void HelloVulkan::createRtShaderBindingTable() -{ - - uint32_t missCount{2}; - uint32_t hitCount{3}; - auto handleCount = 1 + missCount + hitCount; - uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - - // Get the shader group handles - uint32_t dataSize = handleCount * handleSize; - std::vector handles(dataSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); - assert(result == VK_SUCCESS); - - // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. - uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); - - m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member - m_missRegion.stride = handleSizeAligned; - m_missRegion.size = nvh::align_up(missCount * m_missRegion.stride, m_rtProperties.shaderGroupBaseAlignment); - m_hitRegion.stride = nvh::align_up(handleSize + sizeof(HitRecordBuffer), m_rtProperties.shaderGroupHandleAlignment); - m_hitRegion.size = nvh::align_up(hitCount * m_hitRegion.stride, m_rtProperties.shaderGroupBaseAlignment); - - // Allocate a buffer for storing the SBT. - VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. - - // Find the SBT addresses of each group - VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; - VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - m_rgenRegion.deviceAddress = sbtAddress; - m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; - m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; - - // Helper to retrieve the handle data - auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; - - // Map the SBT buffer and write in the handles. - auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); - uint8_t* pData{nullptr}; - uint32_t handleIdx{0}; - // Raygen - pData = pSBTBuffer; - memcpy(pData, getHandle(handleIdx++), handleSize); - // Miss - pData = pSBTBuffer + m_rgenRegion.size; - for(uint32_t c = 0; c < missCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_missRegion.stride; - } - // Hit - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; - memcpy(pData, getHandle(handleIdx++), handleSize); - - auto recordDataSize = sizeof(HitRecordBuffer); - // hit 1 - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size + m_hitRegion.stride; - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += handleSize; - memcpy(pData, &m_hitShaderRecord[0], recordDataSize); // Hit 1 data - - // hit 2 - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size + (2 * m_hitRegion.stride); - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += handleSize; - memcpy(pData, &m_hitShaderRecord[1], recordDataSize); // Hit 2 data - - - m_alloc.unmap(m_rtSBTBuffer); - m_alloc.finalizeAndReleaseStaging(); -} -#endif - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - -#ifdef USE_SBT_WRAPPER - auto& regions = m_sbtWrapper.getRegions(); - vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); -#else - vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); -#endif - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing_manyhits/hello_vulkan.h b/ray_tracing_manyhits/hello_vulkan.h deleted file mode 100644 index c0a5519..0000000 --- a/ray_tracing_manyhits/hello_vulkan.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - - -#define USE_SBT_WRAPPER -#ifdef USE_SBT_WRAPPER -#include "nvvk/sbtwrapper_vk.hpp" -#endif - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - int hitgroup{0}; // Hit group of the instance - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - -#ifdef USE_SBT_WRAPPER - nvvk::SBTWrapper m_sbtWrapper; -#else - nvvk::Buffer m_rtSBTBuffer; - VkStridedDeviceAddressRegionKHR m_rgenRegion{}; - VkStridedDeviceAddressRegionKHR m_missRegion{}; - VkStridedDeviceAddressRegionKHR m_hitRegion{}; - VkStridedDeviceAddressRegionKHR m_callRegion{}; -#endif - - // Push constant for ray tracer - PushConstantRay m_pcRay{}; - - struct HitRecordBuffer - { - glm::vec4 color; - }; - std::vector m_hitShaderRecord; -}; diff --git a/ray_tracing_manyhits/images/manyhits.png b/ray_tracing_manyhits/images/manyhits.png deleted file mode 100644 index eaa90ee..0000000 Binary files a/ray_tracing_manyhits/images/manyhits.png and /dev/null differ diff --git a/ray_tracing_manyhits/images/manyhits2.png b/ray_tracing_manyhits/images/manyhits2.png deleted file mode 100644 index aeb5624..0000000 Binary files a/ray_tracing_manyhits/images/manyhits2.png and /dev/null differ diff --git a/ray_tracing_manyhits/images/manyhits3.png b/ray_tracing_manyhits/images/manyhits3.png deleted file mode 100644 index 7faa476..0000000 Binary files a/ray_tracing_manyhits/images/manyhits3.png and /dev/null differ diff --git a/ray_tracing_manyhits/images/manyhits4.png b/ray_tracing_manyhits/images/manyhits4.png deleted file mode 100644 index 8465702..0000000 Binary files a/ray_tracing_manyhits/images/manyhits4.png and /dev/null differ diff --git a/ray_tracing_manyhits/images/sbt_0.png b/ray_tracing_manyhits/images/sbt_0.png deleted file mode 100644 index 0216305..0000000 Binary files a/ray_tracing_manyhits/images/sbt_0.png and /dev/null differ diff --git a/ray_tracing_manyhits/images/sbt_1.png b/ray_tracing_manyhits/images/sbt_1.png deleted file mode 100644 index 5a5ef47..0000000 Binary files a/ray_tracing_manyhits/images/sbt_1.png and /dev/null differ diff --git a/ray_tracing_manyhits/main.cpp b/ray_tracing_manyhits/main.cpp deleted file mode 100644 index 62d8f7e..0000000 --- a/ray_tracing_manyhits/main.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat({3.937, 3.702, -5.448}, {-1.170, 0.592, -1.674}, {0.000, 1.000, 0.000}); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), - glm::translate(glm::mat4(1), glm::vec3(-1, 0, 0))); - - helloVk.m_instances.push_back({glm::translate(glm::mat4(1), glm::vec3(1, 0, 0)), 0}); // Adding an instance of the Wuson - - - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - - // Hit shader record info - helloVk.m_hitShaderRecord.resize(2); - helloVk.m_hitShaderRecord[0].color = glm::vec4(0, 1, 0, 0); // Green - helloVk.m_hitShaderRecord[1].color = glm::vec4(0, 1, 1, 0); // Cyan - helloVk.m_instances[0].hitgroup = 1; // Wuson 0 - helloVk.m_instances[1].hitgroup = 2; // Wuson 1 - helloVk.m_instances[2].hitgroup = 0; // Plane - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - //helloVk.createRtShaderBindingTable(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_manyhits/shaders/frag_shader.frag b/ray_tracing_manyhits/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_manyhits/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_manyhits/shaders/host_device.h b/ray_tracing_manyhits/shaders/host_device.h deleted file mode 100644 index a22192e..0000000 --- a/ray_tracing_manyhits/shaders/host_device.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_manyhits/shaders/passthrough.vert b/ray_tracing_manyhits/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_manyhits/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_manyhits/shaders/post.frag b/ray_tracing_manyhits/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_manyhits/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_manyhits/shaders/raycommon.glsl b/ray_tracing_manyhits/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing_manyhits/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing_manyhits/shaders/raytrace.rchit b/ray_tracing_manyhits/shaders/raytrace.rchit deleted file mode 100644 index 2eb634e..0000000 --- a/ray_tracing_manyhits/shaders/raytrace.rchit +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_manyhits/shaders/raytrace.rgen b/ray_tracing_manyhits/shaders/raytrace.rgen deleted file mode 100644 index 4802cd0..0000000 --- a/ray_tracing_manyhits/shaders/raytrace.rgen +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0)); -} diff --git a/ray_tracing_manyhits/shaders/raytrace.rmiss b/ray_tracing_manyhits/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_manyhits/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_manyhits/shaders/raytrace2.rchit b/ray_tracing_manyhits/shaders/raytrace2.rchit deleted file mode 100644 index e08f612..0000000 --- a/ray_tracing_manyhits/shaders/raytrace2.rchit +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable - -#include "raycommon.glsl" - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(shaderRecordEXT) buffer sr_ { vec4 shaderRec; }; -// clang-format on - -void main() -{ - prd.hitValue = shaderRec.rgb; -} diff --git a/ray_tracing_manyhits/shaders/raytraceShadow.rmiss b/ray_tracing_manyhits/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_manyhits/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_manyhits/shaders/vert_shader.vert b/ray_tracing_manyhits/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_manyhits/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_manyhits/shaders/wavefront.glsl b/ray_tracing_manyhits/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_manyhits/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_motionblur/CMakeLists.txt b/ray_tracing_motionblur/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_motionblur/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_motionblur/README.md b/ray_tracing_motionblur/README.md deleted file mode 100644 index 545164e..0000000 --- a/ray_tracing_motionblur/README.md +++ /dev/null @@ -1,297 +0,0 @@ -# Motion Blur - -![](images/motionblur.png) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -If you haven't compiled it before, here is the [setup](../docs/setup.md). - -## Beta Feature - -:warning: This feature is in beta and the following are needed: - -* Vulkan Beta Driver: [472.02](https://developer.nvidia.com/vulkan-driver) -* Vulkan SDK: [1.2.189.0](https://vulkan.lunarg.com/sdk/home) - -:warning: This new feature is not fully supported by the validation layer and produces (harmless) error messages. - -## VK_NV_ray_tracing_motion_blur - -This sample shows the usage of the [motion blur extension](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_ray_tracing_motion_blur.html). - -The following changes were made to the [original sample](../ray_tracing__simple): - -* Use trace call with a time parameter. -* Using the various flags to enable motion support in an acceleration structure. -* Support for time-varying vertex positions in a geometry. -* Add motion over time to instances, including scaling, shearing, rotation, and translation (SRT) and matrix motion, while keeping some static. - -The definition of an animation consists in defining the state of the scene at a start time, T0, and at an end time, T1. For example, T0 can be the beginning of a frame and T1 the end of a frame, then rays can be drawn at any intermediate time, for example at t=0.5, in the middle of the frame, and motion blur can be achieved through sampling, using a random t for each ray. - -## Enabling Motion Blur - -### Extensions - -In main.cpp, we add the device extension `VK_NV_ray_tracing_motion_blur` and enable all features. - -```` C - // #NV_Motion_blur - VkPhysicalDeviceRayTracingMotionBlurFeaturesNV rtMotionBlurFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV}; - contextInfo.addDeviceExtension(VK_NV_RAY_TRACING_MOTION_BLUR_EXTENSION_NAME, false, &rtMotionBlurFeatures); // Required for motion blur -```` - -### Pipeline - -When creating the ray tracing pipeline, the `flag` member of `VkRayTracingPipelineCreateInfoKHR` must include `VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV`. - -```` C - rayPipelineInfo.flags = VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV; -```` - -### Scene Objects - -We will use the following four models. The later sections will add matrix animation to two instances of the cube_multi.obj model, -and the plane.obj model will remain static. The third and fourth models are the keyframes for a vertex animation. The cube.obj file represents the -cube at time 0 (T0), and cube_modif.obj is the cube at time 1 (T1). - -```` C - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/cube_modif.obj", defaultSearchPaths, true)); -```` - -## Vertex Varying Motion - -As shown in the image, the positions of the vertices of the left green cube change over time. -We specify this by giving two geometries to the BLAS builder. Setting the geometry at T0 -is done the same way as before. To add the destination keyframe at T1, we make the -`VkAccelerationStructureGeometryTrianglesDataKHR` structure's `pNext` field point to a -`VkAccelerationStructureGeometryMotionTrianglesDataNV` structure. Additionally, we must add -`VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV` to the BLAS build info flags. - -At first we are adding the cube_multi and plane. The geometry of cube_multi is not animated -by itself, but the transformation matrix of its instance is, so we will set its animation -in the TLAS in the Instance Motion section. - -````C -void HelloVulkan::createBottomLevelAS() -{ - // Static geometries - std::vector allBlas; - allBlas.emplace_back(objectToVkGeometryKHR(m_objModel[0])); - allBlas.emplace_back(objectToVkGeometryKHR(m_objModel[1])); -```` - -We then add the cube along with its motion information, which contains a reference to the geometry at time T1 and the motion type flag. This flag indicates the vertices of the geometry are animated. - -````C - // Animated geometry - allBlas.emplace_back(objectToVkGeometryKHR(m_objModel[2])); - // Adding the m_objModel[3] as the destination of m_objModel[2] - VkAccelerationStructureGeometryMotionTrianglesDataNV motionTriangles{ - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV}; - motionTriangles.vertexData.deviceAddress = nvvk::getBufferDeviceAddress(m_device, m_objModel[3].vertexBuffer.buffer); - allBlas[2].asGeometry[0].geometry.triangles.pNext = &motionTriangles; - // Telling that this geometry has motion - allBlas[2].flags = VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV; -```` - -Building all the BLAS remains the same. - -````C - - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} -```` - -## Instance Motion - -Instance motion describes motion in the TLAS, where objects move as a whole. There are 3 types: - -* Static -* Matrix motion -* SRT motion - -The instance array uses [`VkAccelerationStructureMotionInstanceNV`](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkAccelerationStructureMotionInstanceNV.html) instead of `VkAccelerationStructureInstanceKHR`, but since we have a packed structure array, and the stride of the motion structure [must be 160 bytes](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkAccelerationStructureGeometryInstancesDataKHR.html), we create a new structure and derive from `VkAccelerationStructureMotionInstanceNV` and add the missing 8 padding bytes. - -```` C - // VkAccelerationStructureMotionInstanceNV must have a stride of 160 bytes. - // See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkAccelerationStructureGeometryInstancesDataKHR.html - struct VkAccelerationStructureMotionInstanceNVPad : VkAccelerationStructureMotionInstanceNV - { - uint64_t _pad{0}; - }; - static_assert((sizeof(VkAccelerationStructureMotionInstanceNVPad) == 160)); -```` - -All instances will be stored in the vector of `VkAccelerationStructureMotionInstanceNVPad`. The `ObjId` will be the index of the object this instance refers to. - -````C - uint32_t objId; - std::vector tlas; -```` - -### Matrix Motion - -The motion matrix must fill the structure [`VkAccelerationStructureMatrixMotionInstanceNV`](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkAccelerationStructureMatrixMotionInstanceNV.html). We use the transformation matrix stored in the instance for *time 0* and we set the *time 1* with a translation of 0.3 on the X axis. - -```` C - // Cube (moving/matrix translation) - objId = 0; - { - // Position of the instance at T0 and T1 - glm::mat4 matT0 = m_instances[0].transform; - glm::mat4 matT1 = glm::translate(glm::mat4(1),glm::vec3(0.30f, 0.0f, 0.0f)) * matT0; - - VkAccelerationStructureMatrixMotionInstanceNV data; - data.transformT0 = nvvk::toTransformMatrixKHR(matT0); - data.transformT1 = nvvk::toTransformMatrixKHR(matT1); - data.instanceCustomIndex = objId; // gl_InstanceCustomIndexEXT - data.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_instances[objId].objIndex); - data.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - data.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - data.mask = 0xFF; - VkAccelerationStructureMotionInstanceNVPad rayInst; - rayInst.type = VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV; - rayInst.data.matrixMotionInstance = data; - tlas.emplace_back(rayInst); - } -```` - -### SRT Motion - -The SRT motion uses the structure [`VkAccelerationStructureSRTMotionInstanceNV`](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkAccelerationStructureSRTMotionInstanceNV.html) -where it interpolates between two structures [`VkSRTDataNV`](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSRTDataNV.html). In this case, we start with the object translated to [2, 0, 0] and apply a rotation for *time 1*. - -````C -// Cube (moving/SRT rotation) - objId = 0; - { - glm::quatf rot; - rot.from_euler_xyz({0, 0, 0}); - // Position of the instance at T0 and T1 - VkSRTDataNV matT0{}; // Translated to 0,0,2 - matT0.sx = 1.0f; - matT0.sy = 1.0f; - matT0.sz = 1.0f; - matT0.tz = 2.0f; - matT0.qx = rot.x; - matT0.qy = rot.y; - matT0.qz = rot.z; - matT0.qw = rot.w; - VkSRTDataNV matT1 = matT0; // Setting a rotation - rot.from_euler_xyz({glm::radians(10.0f), glm::radians(30.0f), 0.0f}); - matT1.qx = rot.x; - matT1.qy = rot.y; - matT1.qz = rot.z; - matT1.qw = rot.w; - - VkAccelerationStructureSRTMotionInstanceNV data{}; - data.transformT0 = matT0; - data.transformT1 = matT1; - data.instanceCustomIndex = objId; // gl_InstanceCustomIndexEXT - data.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_objInstance[objId].objIndex); - data.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - data.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - data.mask = 0xFF; - VkAccelerationStructureMotionInstanceNVPad rayInst; - rayInst.type = VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV; - rayInst.data.srtMotionInstance = data; - tlas.emplace_back(rayInst); - } -```` - -### Static - -Static instances use the same structure as we normally use with static scenes, `VkAccelerationStructureInstanceKHR`. Static objects are not moving, but they can be deformed, as it is with the cube. - -First the plane is not moving at all - -```` C - // Plane (static) - objId = 1; - { - glm::mat4 matT0 = m_instances[1].transform; - - VkAccelerationStructureInstanceKHR data{}; - data.transform = nvvk::toTransformMatrixKHR(matT0); // Position of the instance - data.instanceCustomIndex = objId; // gl_InstanceCustomIndexEXT - data.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_instances[objId].objIndex); - data.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - data.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - data.mask = 0xFF; - VkAccelerationStructureMotionInstanceNVPad rayInst; - rayInst.type = VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV; - rayInst.data.staticInstance = data; - tlas.emplace_back(rayInst); - } - ```` - -Second the deformed cube is not moving, only its geometry. This was done when setting the BLAS. - -```` C - // Cube+Cubemodif (static) - objId = 2; - { - glm::mat4 matT0 = m_instances[2].transform; - - VkAccelerationStructureInstanceKHR data{}; - data.transform = nvvk::toTransformMatrixKHR(matT0); // Position of the instance - data.instanceCustomIndex = objId; // gl_InstanceCustomIndexEXT - data.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_instances[objId].objIndex); - data.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - data.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - data.mask = 0xFF; - VkAccelerationStructureMotionInstanceNVPad rayInst; - rayInst.type = VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV; - rayInst.data.staticInstance = data; - tlas.emplace_back(rayInst); - } -```` - -### Building - - The building call for the TLAS is similar, only the flag for motion is changing to true. - - ````C - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV, false, true); - ```` - -## Shader - -In the shader, we enable the `GL_NV_ray_tracing_motion_blur` extension. - -```` C -#extension GL_NV_ray_tracing_motion_blur : require -```` - -Then we call `traceRayMotionNV` instead of `traceRayEXT`. The `time` argument must vary between 0 and 1 for each call. - -````C - traceRayMotionNV(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - time, // time - 0 // payload (location = 0) - ); -```` - -We have used some technique from the [jitter cam](../ray_tracing_jitter_cam) to sampling time randomly. -Using random time value for each pixel at each frame gives a nicer look when accumulated over time than using a single time per frame. - -If we were using constant time instead, the image would have a [stuttered motion](https://en.wikipedia.org/wiki/Rotary_disc_shutter) look, like this: - -![](images/rotary_disc_shutter.png) - -:warning: Using motion blur pipeline with all instances static will be slower than using the static pipeline. The performance hit is minor, but optimized applications should use motion blur only where necessary. - -:warning: Calling `traceRayEXT` from `raytrace.rchit` works, and we get motion-blurred shadows without having to call `traceRayMotionNV` in the closest-hit shader. This works only if `traceRayEXT` is called within the execution of a motion trace call. diff --git a/ray_tracing_motionblur/hello_vulkan.cpp b/ray_tracing_motionblur/hello_vulkan.cpp deleted file mode 100644 index c5bcda1..0000000 --- a/ray_tracing_motionblur/hello_vulkan.cpp +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - -#include - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - m_alloc.destroy(m_rtSBTBuffer); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); - resetFrame(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // Static geometries - std::vector allBlas; - allBlas.emplace_back(objectToVkGeometryKHR(m_objModel[0])); // cube multi - allBlas.emplace_back(objectToVkGeometryKHR(m_objModel[1])); // plane - - // Animated geometry - allBlas.emplace_back(objectToVkGeometryKHR(m_objModel[2])); // cube - // Adding the m_objModel[3] as the destination of m_objModel[2] - VkAccelerationStructureGeometryMotionTrianglesDataNV motionTriangles{ - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV}; - motionTriangles.vertexData.deviceAddress = nvvk::getBufferDeviceAddress(m_device, m_objModel[3].vertexBuffer.buffer); // cube_modif - allBlas[2].asGeometry[0].geometry.triangles.pNext = &motionTriangles; - // Telling that this geometry has motion - allBlas[2].flags = VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV; - - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - // VkAccelerationStructureMotionInstanceNV must have a stride of 160 bytes. - // See https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkAccelerationStructureGeometryInstancesDataKHR.html - struct VkAccelerationStructureMotionInstanceNVPad : VkAccelerationStructureMotionInstanceNV - { - uint64_t _pad{0}; - }; - static_assert(sizeof(VkAccelerationStructureMotionInstanceNVPad) == 160); - - // #NV_Motion_blur - uint32_t objId; - std::vector tlas; - - // Cube (moving/matrix translation) - objId = 0; - { - // Position of the instance at T0 and T1 - glm::mat4 matT0 = m_instances[0].transform; - glm::mat4 matT1 = glm::translate(glm::mat4(1), glm::vec3(0.30f, 0.0f, 0.0f)) * matT0; - - VkAccelerationStructureMatrixMotionInstanceNV data; - data.transformT0 = nvvk::toTransformMatrixKHR(matT0); - data.transformT1 = nvvk::toTransformMatrixKHR(matT1); - data.instanceCustomIndex = objId; // gl_InstanceCustomIndexEXT - data.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_instances[objId].objIndex); - data.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - data.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - data.mask = 0xFF; - VkAccelerationStructureMotionInstanceNVPad rayInst; - rayInst.type = VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV; - rayInst.data.matrixMotionInstance = data; - tlas.emplace_back(rayInst); - } - - // Cube (moving/SRT rotation) - objId = 0; - { - // m_instance[3].transform -> no matrix to SRT - glm::quat rot = {1,0,0,0}; - - // Position of the instance at T0 and T1 - VkSRTDataNV matT0{}; // Translated to 0,0,2 - matT0.sx = 1.0f; - matT0.sy = 1.0f; - matT0.sz = 1.0f; - matT0.tz = 2.0f; - matT0.qx = rot.x; - matT0.qy = rot.y; - matT0.qz = rot.z; - matT0.qw = rot.w; - - VkSRTDataNV matT1 = matT0; // Setting a rotation - rot = glm::quat(glm::vec3(glm::radians(10.0f), glm::radians(30.0f), 0.0f)); - matT1.qx = rot.x; - matT1.qy = rot.y; - matT1.qz = rot.z; - matT1.qw = rot.w; - - VkAccelerationStructureSRTMotionInstanceNV data{}; - data.transformT0 = matT0; - data.transformT1 = matT1; - data.instanceCustomIndex = objId; // gl_InstanceCustomIndexEXT - data.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_instances[objId].objIndex); - data.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - data.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - data.mask = 0xFF; - VkAccelerationStructureMotionInstanceNVPad rayInst; - rayInst.type = VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV; - rayInst.data.srtMotionInstance = data; - tlas.emplace_back(rayInst); - } - - // Plane (static) - objId = 1; - { - glm::mat4 matT0 = m_instances[1].transform; - - VkAccelerationStructureInstanceKHR data{}; - data.transform = nvvk::toTransformMatrixKHR(matT0); // Position of the instance - data.instanceCustomIndex = objId; // gl_InstanceCustomIndexEXT - data.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_instances[objId].objIndex); - data.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - data.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - data.mask = 0xFF; - VkAccelerationStructureMotionInstanceNVPad rayInst; - rayInst.type = VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV; - rayInst.data.staticInstance = data; - tlas.emplace_back(rayInst); - } - - - // Cube+Cubemodif (static) - objId = 2; - { - glm::mat4 matT0 = m_instances[2].transform; - - VkAccelerationStructureInstanceKHR data{}; - data.transform = nvvk::toTransformMatrixKHR(matT0); // Position of the instance - data.instanceCustomIndex = objId; // gl_InstanceCustomIndexEXT - data.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(m_instances[objId].objIndex); - data.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - data.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - data.mask = 0xFF; - VkAccelerationStructureMotionInstanceNVPad rayInst; - rayInst.type = VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV; - rayInst.data.staticInstance = data; - tlas.emplace_back(rayInst); - } - - - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV, false, true); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - // #NV_Motion_blur - rayPipelineInfo.flags = VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV; - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - - // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. - if(m_rtProperties.maxRayRecursionDepth <= 1) - { - throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); - } - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// The Shader Binding Table (SBT) -// - getting all shader handles and write them in a SBT buffer -// - Besides exception, this could be always done like this -// See how the SBT buffer is used in run() -// -void HelloVulkan::createRtShaderBindingTable() -{ - auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - // Bytes needed for the SBT. - uint32_t sbtSize = groupCount * groupSizeAligned; - - // Fetch all the shader handles used in the pipeline. This is opaque data,/ so we store it in a vector of bytes. - // The order of handles follow the stage entry. - std::vector shaderHandleStorage(sbtSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); - - assert(result == VK_SUCCESS); - - // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); - - // Map the SBT buffer and write in the handles. - void* mapped = m_alloc.map(m_rtSBTBuffer); - auto* pData = reinterpret_cast(mapped); - for(uint32_t g = 0; g < groupCount; g++) - { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); - pData += groupSizeAligned; - } - m_alloc.unmap(m_rtSBTBuffer); - m_alloc.finalizeAndReleaseStaging(); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - updateFrame(); - if(m_pcRay.frame >= m_maxFrames) - return; - - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - // Size of a program identifier - uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - - VkDeviceAddress sbtAddress = nvvk::getBufferDeviceAddress(m_device, m_rtSBTBuffer.buffer); - - using Stride = VkStridedDeviceAddressRegionKHR; - std::array 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 - - - vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], - m_size.width, m_size.height, 1); - - - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// If the camera matrix or the the fov has changed, resets the frame. -// otherwise, increments frame. -// -void HelloVulkan::updateFrame() -{ - static glm::mat4 refCamMatrix; - static float refFov{CameraManip.getFov()}; - - const auto& m = CameraManip.getMatrix(); - const auto fov = CameraManip.getFov(); - - if(refCamMatrix != m || refFov != fov) - { - resetFrame(); - refCamMatrix = m; - refFov = fov; - } - m_pcRay.frame++; -} - -void HelloVulkan::resetFrame() -{ - m_pcRay.frame = -1; -} diff --git a/ray_tracing_motionblur/hello_vulkan.h b/ray_tracing_motionblur/hello_vulkan.h deleted file mode 100644 index bd9cdf9..0000000 --- a/ray_tracing_motionblur/hello_vulkan.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - // Instance of the OBJ - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {9.5f, 5.5f, -6.5f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - void updateFrame(); - void resetFrame(); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; - - // Push constant for ray tracer - PushConstantRay m_pcRay{}; - - int m_maxFrames{1000}; -}; diff --git a/ray_tracing_motionblur/images/motionblur.png b/ray_tracing_motionblur/images/motionblur.png deleted file mode 100644 index abf50e5..0000000 Binary files a/ray_tracing_motionblur/images/motionblur.png and /dev/null differ diff --git a/ray_tracing_motionblur/images/rotary_disc_shutter.png b/ray_tracing_motionblur/images/rotary_disc_shutter.png deleted file mode 100644 index 8d8e1ee..0000000 Binary files a/ray_tracing_motionblur/images/rotary_disc_shutter.png and /dev/null differ diff --git a/ray_tracing_motionblur/main.cpp b/ray_tracing_motionblur/main.cpp deleted file mode 100644 index dacd253..0000000 --- a/ray_tracing_motionblur/main.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - bool changed{false}; - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - auto& pc = helloVk.m_pcRaster; - changed |= ImGui::RadioButton("Point", &pc.lightType, 0); - ImGui::SameLine(); - 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); - } - - - changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 100); - if(changed) - helloVk.resetFrame(); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat({3.445, 2.151, -2.098}, {0.435, -0.431, 0.705}, {0.000, 1.000, 0.000}); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // #NV_Motion_blur - VkPhysicalDeviceRayTracingMotionBlurFeaturesNV rtMotionBlurFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV}; - contextInfo.addDeviceExtension(VK_NV_RAY_TRACING_MOTION_BLUR_EXTENSION_NAME, false, &rtMotionBlurFeatures); // Required for motion blur - - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.ignoreDebugMessage(0x79de34d4); // Missing Device Extension "VK_NV_ray_tracing_motion_blur" - vkctx.ignoreDebugMessage(0xf69d66f5); // Value of pInfos[0].pGeometries[0].geometry.triangles.pNext must be NULL - vkctx.ignoreDebugMessage(0x938b32); // SPIR-V Extension (SPV_NV_ray_tracing_motion_blur) - vkctx.initInstance(contextInfo); - - - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/cube_modif.obj", defaultSearchPaths, true)); - - // Set the positions of the instances and reuse the last instance (cube_modif) to use cube_multi instead - helloVk.m_instances[1].transform = glm::translate(glm::mat4(1), glm::vec3(0, -1, 0)); - helloVk.m_instances[2].transform = glm::translate(glm::mat4(1), glm::vec3(2, 0, 2)); - helloVk.m_instances[3].objIndex = 0; - helloVk.m_instances[3].transform = glm::translate(glm::mat4(1), glm::vec3(0, 0, 2)); // SRT - unused - - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - helloVk.createRtShaderBindingTable(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - bool changed = false; - // Edit 3 floats representing a color - changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - // Switch between raster and ray tracing - changed |= ImGui::Checkbox("Ray Tracer mode", &useRaytracer); - if(changed) - helloVk.resetFrame(); - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_motionblur/shaders/frag_shader.frag b/ray_tracing_motionblur/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_motionblur/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_motionblur/shaders/host_device.h b/ray_tracing_motionblur/shaders/host_device.h deleted file mode 100644 index bf0ed9e..0000000 --- a/ray_tracing_motionblur/shaders/host_device.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; - int frame; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_motionblur/shaders/passthrough.vert b/ray_tracing_motionblur/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_motionblur/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_motionblur/shaders/post.frag b/ray_tracing_motionblur/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_motionblur/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_motionblur/shaders/random.glsl b/ray_tracing_motionblur/shaders/random.glsl deleted file mode 100644 index ef41f54..0000000 --- a/ray_tracing_motionblur/shaders/random.glsl +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -// Generate a random unsigned int from two unsigned int values, using 16 pairs -// of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis, -// "GPU Random Numbers via the Tiny Encryption Algorithm" -uint tea(uint val0, uint val1) -{ - uint v0 = val0; - uint v1 = val1; - uint s0 = 0; - - for(uint n = 0; n < 16; n++) - { - s0 += 0x9e3779b9; - v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4); - v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e); - } - - return v0; -} - -// Generate a random unsigned int in [0, 2^24) given the previous RNG state -// using the Numerical Recipes linear congruential generator -uint lcg(inout uint prev) -{ - uint LCG_A = 1664525u; - uint LCG_C = 1013904223u; - prev = (LCG_A * prev + LCG_C); - return prev & 0x00FFFFFF; -} - -// Generate a random float in [0, 1) given the previous RNG state -float rnd(inout uint prev) -{ - return (float(lcg(prev)) / float(0x01000000)); -} diff --git a/ray_tracing_motionblur/shaders/raycommon.glsl b/ray_tracing_motionblur/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing_motionblur/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing_motionblur/shaders/raytrace.rchit b/ray_tracing_motionblur/shaders/raytrace.rchit deleted file mode 100644 index 2eb634e..0000000 --- a/ray_tracing_motionblur/shaders/raytrace.rchit +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_motionblur/shaders/raytrace.rgen b/ray_tracing_motionblur/shaders/raytrace.rgen deleted file mode 100644 index 2bc9fef..0000000 --- a/ray_tracing_motionblur/shaders/raytrace.rgen +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_NV_ray_tracing_motion_blur : require - -#include "raycommon.glsl" -#include "host_device.h" -#include "random.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - -const int NBSAMPLES = 10; - -void main() -{ - // Initialize the random number - uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame); - - vec3 hitValues = vec3(0); - - for(int smpl = 0; smpl < NBSAMPLES; smpl++) - { - - float r1 = rnd(seed); - float r2 = rnd(seed); - // Subpixel jitter: send the ray through a different position inside the pixel - // each time, to provide antialiasing. - vec2 subpixel_jitter = pcRay.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2); - - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter; - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - float time = rnd(seed); - // float time = float(smpl)/float(NBSAMPLES); // stuttered motion - prd.hitValue = vec3(0, 0, 0); - - traceRayMotionNV(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - time, // time - 0 // payload (location = 0) - ); - hitValues += prd.hitValue; - } - prd.hitValue = hitValues / NBSAMPLES; - - // Do accumulation over time - if(pcRay.frame > 0) - { - float a = 1.0f / float(pcRay.frame + 1); - vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz; - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f)); - } - else - { - // First frame, replace the value in the buffer - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.f)); - } -} diff --git a/ray_tracing_motionblur/shaders/raytrace.rmiss b/ray_tracing_motionblur/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_motionblur/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_motionblur/shaders/raytraceShadow.rmiss b/ray_tracing_motionblur/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_motionblur/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_motionblur/shaders/vert_shader.vert b/ray_tracing_motionblur/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_motionblur/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_motionblur/shaders/wavefront.glsl b/ray_tracing_motionblur/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_motionblur/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_rayquery/CMakeLists.txt b/ray_tracing_rayquery/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_rayquery/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_rayquery/README.md b/ray_tracing_rayquery/README.md deleted file mode 100644 index 0152b5c..0000000 --- a/ray_tracing_rayquery/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# Ray Query - Tutorial - -![](images/rayquery.png) - -## Tutorial ([Setup](../docs/setup.md)) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -This extension is allowing to execute ray intersection queries in any shader stages. In this example, we will add -ray queries [(GLSL_EXT_ray_query)](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GLSL_EXT_ray_query.txt) to the fragment shader to cast shadow rays. - -In the contrary to all other examples, with this one, we are removing code. There are no need to have a SBT and a raytracing pipeline, the only thing that -will matter, is the creation of the acceleration structure. - -Starting from the end of the tutorial, [ray_tracing__simple](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/tree/master/ray_tracing__simple) we will remove -all functions that were dedicated to ray tracing and keep only the construction of the BLAS and TLAS. - -## Cleanup - -First, let's remove all extra code - -### hello_vulkan (header) - -Remove most functions and members to keep only what is need to create the acceleration structure: - -~~~~ C++ - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; -~~~~ - -### hello_vulkan (source) - -From the source code, remove the code for all functions that was previously removed. - -### Shaders - -You can safely remove all raytrace.* shaders - -## Support for Fragment shader - -In `HelloVulkan::createDescriptorSetLayout`, add the acceleration structure to the description layout to have access to the acceleration structure directly in the fragment shader. - -~~~~ C++ - // The top level acceleration structure - m_descSetLayoutBind.addBinding(eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT); -~~~~ - -But since we will use only one descriptor set, change the binding value or `eTlas` to 3, such that binding will look like this - -~~~~ C++ - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2, // Access to textures - eTlas = 3 // Top-level acceleration structure -~~~~ - -In `HelloVulkan::updateDescriptorSet`, write the value to the descriptor set. - -~~~~ C++ - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, eTlas, &descASInfo)); -~~~~ - -### Shader - -The last modification is in the fragment shader, where we will add the ray intersection query to trace shadow rays. - -First, the version has bumpped to 460 - -~~~~ C++ -#version 460 -~~~~ - -Then we need to add new extensions - -~~~~ C++ -#extension GL_EXT_ray_tracing : enable -#extension GL_EXT_ray_query : enable -~~~~ - -We have to add the layout to access the top level acceleration structure. - -~~~~ C++ -layout(binding = eTlas) uniform accelerationStructureEXT topLevelAS; -~~~~ - -At the end of the shader, add the following code to initiate the ray query. As we are only interested to know if the ray -has hit something, we can keep the minimal. - -~~~~ C++ -// Ray Query for shadow -vec3 origin = i_worldPos; -vec3 direction = L; // vector to light -float tMin = 0.01f; -float tMax = lightDistance; - -// Initializes a ray query object but does not start traversal -rayQueryEXT rayQuery; -rayQueryInitializeEXT(rayQuery, topLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tMin, direction, tMax); - -// Start traversal: return false if traversal is complete -while(rayQueryProceedEXT(rayQuery)) -{ -} - -// Returns type of committed (true) intersection -if(rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT) -{ - // Got an intersection == Shadow - o_color *= 0.1; -} -~~~~ diff --git a/ray_tracing_rayquery/hello_vulkan.cpp b/ray_tracing_rayquery/hello_vulkan.cpp deleted file mode 100644 index 83d0642..0000000 --- a/ray_tracing_rayquery/hello_vulkan.cpp +++ /dev/null @@ -1,681 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - // The top level acceleration structure - m_descSetLayoutBind.addBinding(eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, eTlas, &descASInfo)); - - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} diff --git a/ray_tracing_rayquery/hello_vulkan.h b/ray_tracing_rayquery/hello_vulkan.h deleted file mode 100644 index d936ef1..0000000 --- a/ray_tracing_rayquery/hello_vulkan.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; -}; diff --git a/ray_tracing_rayquery/images/rayquery.png b/ray_tracing_rayquery/images/rayquery.png deleted file mode 100644 index c9f160a..0000000 Binary files a/ray_tracing_rayquery/images/rayquery.png and /dev/null differ diff --git a/ray_tracing_rayquery/main.cpp b/ray_tracing_rayquery/main.cpp deleted file mode 100644 index d42f8d9..0000000 --- a/ray_tracing_rayquery/main.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME, false, &rayQueryFeatures); - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - - // Need the Top level AS - helloVk.updateDescriptorSet(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_rayquery/shaders/frag_shader.frag b/ray_tracing_rayquery/shaders/frag_shader.frag deleted file mode 100644 index 701fd39..0000000 --- a/ray_tracing_rayquery/shaders/frag_shader.frag +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require -#extension GL_EXT_ray_tracing : enable -#extension GL_EXT_ray_query : enable - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -layout(binding = eTlas) uniform accelerationStructureEXT topLevelAS; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightDistance; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - lightDistance = d; - } - else - { - L = normalize(pcRaster.lightPosition); - lightDistance = 10000; - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); - - - // Ray Query for shadow - vec3 origin = i_worldPos; - vec3 direction = L; // vector to light - float tMin = 0.01f; - float tMax = lightDistance; - - // Initializes a ray query object but does not start traversal - rayQueryEXT rayQuery; - rayQueryInitializeEXT(rayQuery, topLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tMin, direction, tMax); - - // Start traversal: return false if traversal is complete - while(rayQueryProceedEXT(rayQuery)) - { - } - - // Returns type of committed (true) intersection - if(rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT) - { - // Got an intersection == Shadow - o_color *= 0.1; - } -} diff --git a/ray_tracing_rayquery/shaders/host_device.h b/ray_tracing_rayquery/shaders/host_device.h deleted file mode 100644 index 3175203..0000000 --- a/ray_tracing_rayquery/shaders/host_device.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2, // Access to textures - eTlas = 3 // Top-level acceleration structure -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_rayquery/shaders/passthrough.vert b/ray_tracing_rayquery/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_rayquery/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_rayquery/shaders/post.frag b/ray_tracing_rayquery/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_rayquery/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_rayquery/shaders/raycommon.glsl b/ray_tracing_rayquery/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing_rayquery/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing_rayquery/shaders/vert_shader.vert b/ray_tracing_rayquery/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_rayquery/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_rayquery/shaders/wavefront.glsl b/ray_tracing_rayquery/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_rayquery/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_reflections/CMakeLists.txt b/ray_tracing_reflections/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_reflections/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_reflections/README.md b/ray_tracing_reflections/README.md deleted file mode 100644 index f88b9f9..0000000 --- a/ray_tracing_reflections/README.md +++ /dev/null @@ -1,246 +0,0 @@ -# Reflections - Tutorial - -![](images/reflections.png) - -## Tutorial ([Setup](../docs/setup.md)) - -This is an extension of the Vulkan ray tracing [tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html). - -## Setting Up the scene - -First, we will create a scene with two reflective planes and a multicolored cube in the center. Change the `helloVk.loadModel` calls in `main()` to - -~~~~ C++ - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true), - glm::translate(glm::mat4(1),glm::vec3(-2, 0, 0)) - * glm::scale(glm::mat4(1.f),glm::vec3(.1f, 5.f, 5.f))); - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true), - glm::translate(glm::mat4(1),glm::vec3(2, 0, 0)) - * glm::scale(glm::mat4(1.f),glm::vec3(.1f, 5.f, 5.f))); - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), - glm::translate(glm::mat4(1),glm::vec3(0, -1, 0))); -~~~~ - -Then find `cube.mtl` in `media/scenes` and modify the material to be 95% reflective, without any diffuse -contribution: - -~~~~ C++ -newmtl cube_instance_material -illum 3 -d 1 -Ns 32 -Ni 0 -Ka 0 0 0 -Kd 0 0 0 -Ks 0.95 0.95 0.95 -~~~~ - -## Recursive Reflections - -Vulkan ray tracing allows recursive calls to traceRayEXT, up to a limit defined by `VkPhysicalDeviceRayTracingPropertiesKHR`. - -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++ - rayPipelineInfo.maxPipelineRayRecursionDepth = std::max(10u, m_rtProperties.maxRecursionDepth); // Ray depth -~~~~ - -### `raycommon.glsl` - -We will need to track the depth and the attenuation of the ray. -In the `hitPayload` struct in `raycommon.glsl`, add the following: - -~~~~ C++ - int depth; - vec3 attenuation; -~~~~ - -### `raytrace.rgen` - -In the ray generation shader, we will initialize all payload values before calling `traceRayEXT`. - -~~~~ C++ - prd.depth = 0; - prd.hitValue = vec3(0); - prd.attenuation = vec3(1.f, 1.f, 1.f); -~~~~ - -### `raytrace.rchit` - -At the end of the closest hit shader, before setting `prd.hitValue`, we need to shoot a ray if the material is reflective. - -~~~~ C++ - // Reflection - if(mat.illum == 3 && prd.depth < 10) - { - vec3 origin = worldPos; - vec3 rayDir = reflect(gl_WorldRayDirectionEXT, normal); - prd.attenuation *= mat.specular; - - prd.depth++; - traceRayEXT(topLevelAS, // acceleration structure - gl_RayFlagsNoneEXT, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin, // ray origin - 0.1, // ray min range - rayDir, // ray direction - 100000.0, // ray max range - 0 // payload (location = 0) - ); - prd.depth--; - } -~~~~ - -The calculated `hitValue` needs to be accumulated, since the payload is global for the -entire execution from raygen, so change the last line of `main()` to - -~~~~ C++ -prd.hitValue += vec3(attenuation * lightIntensity * (diffuse + specular)) * prd.attenuation; -~~~~ - -### `raytrace.rmiss` - -Finally, the miss shader also needs to attenuate its contribution: - -~~~~ C++ - prd.hitValue = clearColor.xyz * 0.8 * prd.attenuation; -~~~~ - -### Working, but limited - -This is working, but it is limited to the number of recursions the GPU can do, and could also impact performance. Trying to go over the limit of recursions would eventually generate a device lost error. - -## Iterative Reflections - -Instead of dispatching new rays from the closest hit shader, we will return the information in the payload to shoot new rays if needed. - -### 'raycommon.glsl' - -Enhance the structure to add information to start new rays if wanted. - -~~~~ C++ - int done; - vec3 rayOrigin; - vec3 rayDir; -~~~~ - -### `raytrace.rgen` - -Initialize the new members of the payload: - -~~~~ C++ - prd.done = 1; - prd.rayOrigin = origin.xyz; - prd.rayDir = direction.xyz; -~~~~ - -Instead of calling traceRayEXT only once, we will call it in a loop until we are done. - -Wrap the trace call in `raytrace.rgen` like this: - -~~~~ C++ - vec3 hitValue = vec3(0); - for(;;) - { - traceRayEXT( /*.. */); - - hitValue += prd.hitValue * prd.attenuation; - - prd.depth++; - if(prd.done == 1 || prd.depth >= 10) - break; - - origin.xyz = prd.rayOrigin; - direction.xyz = prd.rayDir; - prd.done = 1; // Will stop if a reflective material isn't hit - } -~~~~ - -And make sure to write the correct value - -~~~~ C++ -imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue, 1.0)); -~~~~ - -### `raytrace.rchit` - -We no longer need to shoot rays from the closest hit shader, so we can replace the block at the end with - -~~~~ C++ - if(mat.illum == 3) - { - vec3 origin = worldPos; - vec3 rayDir = reflect(gl_WorldRayDirectionEXT, normal); - prd.attenuation *= mat.specular; - prd.done = 0; - prd.rayOrigin = origin; - prd.rayDir = rayDir; - } -~~~~ - -The calculation of the hitValue also no longer needs to be additive, or take attenuation into account: - -~~~~ C++ - prd.hitValue = vec3(attenuation * lightIntensity * (diffuse + specular)); -~~~~ - -### `raytrace.rmiss` - -Since the ray generation shader now handles attenuation, we no longer need to attenuate the value returned in the miss shader: - -~~~~ C++ - prd.hitValue = clearColor.xyz * 0.8; -~~~~ - -### Max Recursion - -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++ - rayPipelineInfo.maxPipelineRayRecursionDepth = 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. - -## Controlling Depth - -As an extra, we can also add UI to control the maximum depth. - -In the `PushConstantRay` structure, we can add a new `maxDepth` member to pass to the shader. - -~~~~ C++ -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; - int maxDepth; -}; -~~~~ - -And we can set a default value to 10, in `hello_vulkan.h` - -~~~~ C++ -PushConstantRay m_pcRay{{}, {}, 0, 0, 10}; -~~~~ - - -In the `raytrace.rgen` shader, we test for the value for when to stop - -~~~~ C++ - if(prd.done == 1 || prd.depth >= pushC.maxDepth) - break; -~~~~ - -Finally, in `main.cpp` after the `renderUI()` function call, we will add a slider to control the depth value. - -~~~~ C++ - ImGui::SliderInt("Max Depth", &helloVk.m_pcRay.maxDepth, 1, 50); -~~~~ - diff --git a/ray_tracing_reflections/hello_vulkan.cpp b/ray_tracing_reflections/hello_vulkan.cpp deleted file mode 100644 index c9a6a95..0000000 --- a/ray_tracing_reflections/hello_vulkan.cpp +++ /dev/null @@ -1,930 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - m_alloc.destroy(m_rtSBTBuffer); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, - eShaderGroupCount - }; - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - // Hit Group - Closest Hit - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stages[eClosestHit] = stage; - - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // closest hit shader - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit; - m_rtShaderGroups.push_back(group); - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// The Shader Binding Table (SBT) -// - getting all shader handles and write them in a SBT buffer -// - Besides exception, this could be always done like this -// -void HelloVulkan::createRtShaderBindingTable() -{ - uint32_t missCount{2}; - uint32_t hitCount{1}; - auto handleCount = 1 + missCount + hitCount; - uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - - // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. - uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); - - m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member - m_missRegion.stride = handleSizeAligned; - m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - m_hitRegion.stride = handleSizeAligned; - m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); - - // Get the shader group handles - uint32_t dataSize = handleCount * handleSize; - std::vector handles(dataSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); - assert(result == VK_SUCCESS); - - // Allocate a buffer for storing the SBT. - VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT - | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. - - // Find the SBT addresses of each group - VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; - VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - m_rgenRegion.deviceAddress = sbtAddress; - m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; - m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; - - // Helper to retrieve the handle data - auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; - - // Map the SBT buffer and write in the handles. - auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); - uint8_t* pData{nullptr}; - uint32_t handleIdx{0}; - // Raygen - pData = pSBTBuffer; - memcpy(pData, getHandle(handleIdx++), handleSize); - // Miss - pData = pSBTBuffer + m_rgenRegion.size; - for(uint32_t c = 0; c < missCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_missRegion.stride; - } - // Hit - pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; - for(uint32_t c = 0; c < hitCount; c++) - { - memcpy(pData, getHandle(handleIdx++), handleSize); - pData += m_hitRegion.stride; - } - - m_alloc.unmap(m_rtSBTBuffer); - m_alloc.finalizeAndReleaseStaging(); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - - vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); - - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing_reflections/hello_vulkan.h b/ray_tracing_reflections/hello_vulkan.h deleted file mode 100644 index 477fe43..0000000 --- a/ray_tracing_reflections/hello_vulkan.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void createRtShaderBindingTable(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - - nvvk::Buffer m_rtSBTBuffer; - VkStridedDeviceAddressRegionKHR m_rgenRegion{}; - VkStridedDeviceAddressRegionKHR m_missRegion{}; - VkStridedDeviceAddressRegionKHR m_hitRegion{}; - VkStridedDeviceAddressRegionKHR m_callRegion{}; - - // Push constant for ray tracer - PushConstantRay m_pcRay{{}, {}, 0, 0, 10}; -}; diff --git a/ray_tracing_reflections/images/reflections.png b/ray_tracing_reflections/images/reflections.png deleted file mode 100644 index 5453183..0000000 Binary files a/ray_tracing_reflections/images/reflections.png and /dev/null differ diff --git a/ray_tracing_reflections/main.cpp b/ray_tracing_reflections/main.cpp deleted file mode 100644 index 224e2a2..0000000 --- a/ray_tracing_reflections/main.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true), - glm::translate(glm::mat4(1), glm::vec3(-2, 0, 0)) * glm::scale(glm::mat4(1.f), glm::vec3(.1f, 5.f, 5.f))); - helloVk.loadModel(nvh::findFile("media/scenes/cube.obj", defaultSearchPaths, true), - glm::translate(glm::mat4(1), glm::vec3(2, 0, 0)) * glm::scale(glm::mat4(1.f), glm::vec3(.1f, 5.f, 5.f))); - helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true), - glm::translate(glm::mat4(1), glm::vec3(0, -1, 0))); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - helloVk.createRtShaderBindingTable(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::SliderInt("Max Depth", &helloVk.m_pcRay.maxDepth, 1, 50); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_reflections/shaders/frag_shader.frag b/ray_tracing_reflections/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_reflections/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_reflections/shaders/host_device.h b/ray_tracing_reflections/shaders/host_device.h deleted file mode 100644 index 90bf9a8..0000000 --- a/ray_tracing_reflections/shaders/host_device.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; - int maxDepth; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_reflections/shaders/passthrough.vert b/ray_tracing_reflections/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_reflections/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_reflections/shaders/post.frag b/ray_tracing_reflections/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_reflections/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_reflections/shaders/raycommon.glsl b/ray_tracing_reflections/shaders/raycommon.glsl deleted file mode 100644 index 46178f6..0000000 --- a/ray_tracing_reflections/shaders/raycommon.glsl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; - int depth; - vec3 attenuation; - int done; - vec3 rayOrigin; - vec3 rayDir; -}; diff --git a/ray_tracing_reflections/shaders/raytrace.rchit b/ray_tracing_reflections/shaders/raytrace.rchit deleted file mode 100644 index ba9a116..0000000 --- a/ray_tracing_reflections/shaders/raytrace.rchit +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - - // Reflection - if(mat.illum == 3) - { - vec3 origin = worldPos; - vec3 rayDir = reflect(gl_WorldRayDirectionEXT, worldNrm); - prd.attenuation *= mat.specular; - prd.done = 0; - prd.rayOrigin = origin; - prd.rayDir = rayDir; - } - - prd.hitValue = vec3(attenuation * lightIntensity * (diffuse + specular)); -} diff --git a/ray_tracing_reflections/shaders/raytrace.rgen b/ray_tracing_reflections/shaders/raytrace.rgen deleted file mode 100644 index e759534..0000000 --- a/ray_tracing_reflections/shaders/raytrace.rgen +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; - -// clang-format on - - -void main() -{ - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - prd.depth = 0; - prd.hitValue = vec3(0); - prd.attenuation = vec3(1.f, 1.f, 1.f); - prd.done = 1; - prd.rayOrigin = origin.xyz; - prd.rayDir = direction.xyz; - - vec3 hitValue = vec3(0); - for(;;) - { - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - hitValue += prd.hitValue * prd.attenuation; - - prd.depth++; - if(prd.done == 1 || prd.depth >= pcRay.maxDepth) - break; - - origin.xyz = prd.rayOrigin; - direction.xyz = prd.rayDir; - prd.done = 1; // Will stop if a reflective material isn't hit - } - - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue, 1.0)); -} diff --git a/ray_tracing_reflections/shaders/raytrace.rmiss b/ray_tracing_reflections/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_reflections/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_reflections/shaders/raytraceShadow.rmiss b/ray_tracing_reflections/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_reflections/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_reflections/shaders/vert_shader.vert b/ray_tracing_reflections/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_reflections/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_reflections/shaders/wavefront.glsl b/ray_tracing_reflections/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_reflections/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -} diff --git a/ray_tracing_specialization/CMakeLists.txt b/ray_tracing_specialization/CMakeLists.txt deleted file mode 100644 index 1bf130c..0000000 --- a/ray_tracing_specialization/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -#***************************************************************************** -# Copyright 2020 NVIDIA Corporation. All rights reserved. -#***************************************************************************** - -cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR) - -#-------------------------------------------------------------------------------------------------- -# Project setting -get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) -set(PROJNAME vk_${PROJNAME}_KHR) -project(${PROJNAME} LANGUAGES C CXX) -message(STATUS "-------------------------------") -message(STATUS "Processing Project ${PROJNAME}:") - - -#-------------------------------------------------------------------------------------------------- -# C++ target and defines -set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJNAME}) -_add_project_definitions(${PROJNAME}) - - -#-------------------------------------------------------------------------------------------------- -# Source files for this project -# -file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c) -file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*) -list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON}) -include_directories(${TUTO_KHR_DIR}/common) - - -#-------------------------------------------------------------------------------------------------- -# GLSL to SPIR-V custom build -compile_glsl_directory( - SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - DST "${CMAKE_CURRENT_SOURCE_DIR}/spv" - VULKAN_TARGET "vulkan1.2" - DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} - ) - - -#-------------------------------------------------------------------------------------------------- -# Sources -target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES}) -target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES}) -target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Sub-folders in Visual Studio -# -source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES}) -source_group("Sources" FILES ${SOURCE_FILES}) -source_group("Headers" FILES ${HEADER_FILES}) -source_group("Shader Sources" FILES ${GLSL_SOURCES}) -source_group("Shader Headers" FILES ${GLSL_HEADERS}) - - -#-------------------------------------------------------------------------------------------------- -# Linkage -# -target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core) - -foreach(DEBUGLIB ${LIBRARIES_DEBUG}) - target_link_libraries(${PROJNAME} debug ${DEBUGLIB}) -endforeach(DEBUGLIB) - -foreach(RELEASELIB ${LIBRARIES_OPTIMIZED}) - target_link_libraries(${PROJNAME} optimized ${RELEASELIB}) -endforeach(RELEASELIB) - -#-------------------------------------------------------------------------------------------------- -# copies binaries that need to be put next to the exe files (ZLib, etc.) -# -_finalize_target( ${PROJNAME} ) - - -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv") -install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv") diff --git a/ray_tracing_specialization/README.md b/ray_tracing_specialization/README.md deleted file mode 100644 index 18b654a..0000000 --- a/ray_tracing_specialization/README.md +++ /dev/null @@ -1,268 +0,0 @@ -# Specialization Constants - -![](images/specialization.png) - -In Vulkans, shaders are compiled to Spir-V, but the driver completes optimization during pipeline creation. -Having specialization constants in a shader, is like having #defines that can be changed when pipeline creation is submitted. - -In this example, we will add three specialization constants with all possible permutations. - -* USE_DIFFUSE: to add or not the diffuse contribution -* USE_SPECULAR: to add or not the specular contribution -* TRACE_SHADOW: to trace or not a shadow ray - -## Shader - -In the closest hit shader (`raytrace.chit`), we will add the three constants. Note that we are using `int` only because the tiny helper class later is made for `int` values. - -~~~~ C -layout(constant_id = 0) const int USE_DIFFUSE = 1; -layout(constant_id = 1) const int USE_SPECULAR = 1; -layout(constant_id = 2) const int TRACE_SHADOW = 1; -~~~~ - -And later in the code, we branch based on the values. The modification of the shader will look like this. - -~~~~ C - // Diffuse - vec3 diffuse = vec3(0); - if(USE_DIFFUSE == 1) - { - diffuse = computeDiffuse(mat, L, normal); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + scnDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y - + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(normal, L) > 0) - { - if(TRACE_SHADOW == 1) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT - | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - } - else - isShadowed = false; - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - if(USE_SPECULAR == 1) - { - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, normal); - } - } - } - ~~~~ - -Running the example will not change anything, since by default it will do everything as it usually does. - -## Pipeline - -The specialization constants must be attached to their stages described by `VkPipelineShaderStageCreateInfo` structs. -See [specialization contants reference](https://www.khronos.org/registry/vulkan/specs/1.1-khr-extensions/html/chap10.html#pipelines-specialization-constants) - -In our example, we will have only integers for constant data. There are various ways to do this, but here is the helper class we will be using to add as many constant IDs and values as we want. We will add specialization constants by calling this class's add function with a constant ID and a value, or with a vector of pairs of IDs and values. - -~~~~ C -////////////////////////////////////////////////////////////////////////// -// Helper to generate specialization info -// -class Specialization -{ -public: - void add(uint32_t constantID, int32_t value) - { - spec_values.push_back(value); - VkSpecializationMapEntry entry; - entry.constantID = constantID; - entry.size = sizeof(int32_t); - entry.offset = static_cast(spec_entries.size() * sizeof(int32_t)); - spec_entries.emplace_back(entry); - } - - void add(const std::vector>& const_values) - { - for(const auto& v : const_values) - add(v.first, v.second); - } - - VkSpecializationInfo* getSpecialization() - { - spec_info.dataSize = static_cast(spec_values.size() * sizeof(int32_t)); - spec_info.pData = spec_values.data(); - spec_info.mapEntryCount = static_cast(spec_entries.size()); - spec_info.pMapEntries = spec_entries.data(); - return &spec_info; - } - -private: - std::vector spec_values; - std::vector spec_entries; - VkSpecializationInfo spec_info; -}; -~~~~ - -In `HelloVulkan::createRtPipeline()`, we will create 8 specialization of the closest hit shader. -So the number of stages, will be 11 instead of 4. - -~~~~ C - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, // <---- 8 specialization of this one - eShaderGroupCount = 11 - }; -~~~~ - -Then create a `Specialization` for each of the 8 on/off permutations of the 3 constants. - -~~~~ C - // Specialization - std::vector specializations(8); - for(int i = 0; i < 8; i++) - { - int a = ((i >> 2) % 2) == 1; - int b = ((i >> 1) % 2) == 1; - int c = ((i >> 0) % 2) == 1; - specializations[i].add({{0, a}, {1, b}, {2, c}}); - } -~~~~ - -Now the shader group will be created 8 times, each with a different specialization. - -~~~~ C - // Hit Group - Closest Hit - // Create many variation of the closest hit - for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) - { - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stage.pSpecializationInfo = specializations[s].getSpecialization(); - stages[eClosestHit + s] = stage; - } -~~~~ - -**Tip** : We can avoid to create 8 shader modules, but we would have to properly deal with the - deletion of them at the end of the function. - -We will also modify the creation of the hit group to create as many HIT shader groups as we have specializations. This will give us the ability later to choose which 'specialization' we want to use. - -~~~~ C - // Hit Group - Closest Hit + AnyHit - // Creating many Hit groups, one for each specialization - for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) - { - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit + s; // Using variation of the closest hit - m_rtShaderGroups.push_back(group); - } -~~~~ - -**Note**, it is important that the data and structures are not created on the stack inside the loop, -because we are passing the data address and specialization information, so all this would become -invalid when the pipeline is created. - -## Using Specialization - -If you would run the sample, nothing would have changed. This is because each TLAS's `hitGroupId` is set to `0`. -A quick test would be to change the value to `4`, corresponding to only using diffuse. - -~~~~ C -rayInst.hitGroupId = 4; // We will use the same hit group for all objects -~~~~ - -Knowing the type of material each object is using, it would be possible to choose the appropriate -specialization for each object. - -## Interactive Change - -In our example, we will allow to choose globally the specialization for all objects. To do this, we will add -a new entry to the push constants structure of `PushConstantRay`. - -At the end of the structures, add - -~~~~ C -int specialization; -~~~~ - -and in the `hello_vulkan.h`, initialize the member to 7 (all) - -~~~~C - PushConstantRay m_pcRay{{}, {}, 0, 0, 7}; -~~~~ - -In `raytrace.rgen`, we will use this new value to offset the hit group. Instead of always taking the hit group 0, it will -use the one we choose. - -When we call trace, we will use the specialization value to change the SBT offset. - -~~~~ C - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - pushC.specialization, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); -~~~~ - -Now we only need UI to change interactively the value. - -In main.cpp `renderUI()`, add the following code. - -~~~~ C - // Specialization - ImGui::SliderInt("Specialization", &helloVk.m_pcRay.specialization, 0, 7); - int s = helloVk.m_pcRay.specialization; - int a = ((s >> 2) % 2) == 1; - int b = ((s >> 1) % 2) == 1; - int c = ((s >> 0) % 2) == 1; - ImGui::Checkbox("Use Diffuse", (bool*)&a); - ImGui::Checkbox("Use Specular", (bool*)&b); - ImGui::Checkbox("Trace shadow", (bool*)&c); - helloVk.m_pcRay.specialization = (a << 2) + (b << 1) + c; -~~~~ - -## References - -* Pipelines [Specialization Constants](https://www.khronos.org/registry/vulkan/specs/1.1-khr-extensions/html/chap10.html#pipelines-specialization-constants) -* [VkSpecializationInfo](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSpecializationInfo.html) -* [VkSpecializationMapEntry](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSpecializationMapEntry.html) diff --git a/ray_tracing_specialization/hello_vulkan.cpp b/ray_tracing_specialization/hello_vulkan.cpp deleted file mode 100644 index 0918a59..0000000 --- a/ray_tracing_specialization/hello_vulkan.cpp +++ /dev/null @@ -1,926 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include -#include - - -#define STB_IMAGE_IMPLEMENTATION -#include "obj_loader.h" -#include "stb_image.h" - -#include "hello_vulkan.h" -#include "nvh/alignment.hpp" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/images_vk.hpp" -#include "nvvk/pipeline_vk.hpp" -#include "nvvk/renderpasses_vk.hpp" -#include "nvvk/shaders_vk.hpp" -#include "nvvk/buffers_vk.hpp" - -extern std::vector defaultSearchPaths; - - -//-------------------------------------------------------------------------------------------------- -// Keep the handle on the device -// Initialize the tool to do all our allocations: buffers, images -// -void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) -{ - AppBaseVk::setup(instance, device, physicalDevice, queueFamily); - m_alloc.init(instance, device, physicalDevice); - m_debug.setup(m_device); - m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice); -} - -//-------------------------------------------------------------------------------------------------- -// Called at each frame to update the camera matrix -// -void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf) -{ - // Prepare new UBO contents on host. - const float aspectRatio = m_size.width / static_cast(m_size.height); - GlobalUniforms hostUBO = {}; - const auto& view = CameraManip.getMatrix(); - glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f); - proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK). - - hostUBO.viewProj = proj * view; - hostUBO.viewInverse = glm::inverse(view); - hostUBO.projInverse = glm::inverse(proj); - - // UBO on the device, and what stages access it. - VkBuffer deviceUBO = m_bGlobals.buffer; - auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR; - - // Ensure that the modified UBO is not visible to previous frames. - VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - beforeBarrier.buffer = deviceUBO; - beforeBarrier.offset = 0; - beforeBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &beforeBarrier, 0, nullptr); - - - // Schedule the host-to-device upload. (hostUBO is copied into the cmd - // buffer so it is okay to deallocate when the function returns). - vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO); - - // Making sure the updated UBO will be visible. - VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER}; - afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - afterBarrier.buffer = deviceUBO; - afterBarrier.offset = 0; - afterBarrier.size = sizeof(hostUBO); - vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0, - nullptr, 1, &afterBarrier, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Describing the layout pushed when rendering -// -void HelloVulkan::createDescriptorSetLayout() -{ - auto nbTxt = static_cast(m_textures.size()); - - // Camera matrices - m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR); - // Obj descriptions - m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - // Textures - m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt, - VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); - - - m_descSetLayout = m_descSetLayoutBind.createLayout(m_device); - m_descPool = m_descSetLayoutBind.createPool(m_device, 1); - m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout); -} - -//-------------------------------------------------------------------------------------------------- -// Setting up the buffers in the descriptor set -// -void HelloVulkan::updateDescriptorSet() -{ - std::vector writes; - - // Camera matrices and scene description - VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif)); - - VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE}; - writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc)); - - // All texture samplers - std::vector diit; - for(auto& texture : m_textures) - { - diit.emplace_back(texture.descriptor); - } - writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data())); - - // Writing the information - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the pipeline layout -// -void HelloVulkan::createGraphicsPipeline() -{ - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)}; - - // Creating the Pipeline Layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_descSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout); - - - // Creating the Pipeline - std::vector paths = defaultSearchPaths; - nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass); - gpb.depthStencilState.depthTestEnable = true; - gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT); - gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - gpb.addBindingDescription({0, sizeof(VertexObj)}); - gpb.addAttributeDescriptions({ - {0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, pos))}, - {1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, nrm))}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexObj, color))}, - {3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexObj, texCoord))}, - }); - - m_graphicsPipeline = gpb.createPipeline(); - m_debug.setObjectName(m_graphicsPipeline, "Graphics"); -} - -//-------------------------------------------------------------------------------------------------- -// Loading the OBJ file and setting up all buffers -// -void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform) -{ - LOGI("Loading File: %s \n", filename.c_str()); - ObjLoader loader; - loader.loadModel(filename); - - // Converting from Srgb to linear - for(auto& m : loader.m_materials) - { - m.ambient = glm::pow(m.ambient, glm::vec3(2.2f)); - m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f)); - m.specular = glm::pow(m.specular, glm::vec3(2.2f)); - } - - ObjModel model; - model.nbIndices = static_cast(loader.m_indices.size()); - model.nbVertices = static_cast(loader.m_vertices.size()); - - // Create the buffers on Device and copy vertices, indices and materials - nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer(); - VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures - flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags); - model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags); - model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag); - // Creates all textures found and find the offset for this model - auto txtOffset = static_cast(m_textures.size()); - createTextureImages(cmdBuf, loader.m_textures); - cmdBufGet.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - - std::string objNb = std::to_string(m_objModel.size()); - m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb))); - m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb))); - m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb))); - m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb))); - - // Keeping transformation matrix of the instance - ObjInstance instance; - instance.transform = transform; - instance.objIndex = static_cast(m_objModel.size()); - m_instances.push_back(instance); - - // Creating information for device access - ObjDesc desc; - desc.txtOffset = txtOffset; - desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer); - desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer); - - // Keeping the obj host model and device description - m_objModel.emplace_back(model); - m_objDesc.emplace_back(desc); -} - - -//-------------------------------------------------------------------------------------------------- -// Creating the uniform buffer holding the camera matrices -// - Buffer is host visible -// -void HelloVulkan::createUniformBuffer() -{ - m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - m_debug.setObjectName(m_bGlobals.buffer, "Globals"); -} - -//-------------------------------------------------------------------------------------------------- -// Create a storage buffer containing the description of the scene elements -// - Which geometry is used by which instance -// - Transformation -// - Offset for texture -// -void HelloVulkan::createObjDescriptionBuffer() -{ - nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex); - - auto cmdBuf = cmdGen.createCommandBuffer(); - m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - cmdGen.submitAndWait(cmdBuf); - m_alloc.finalizeAndReleaseStaging(); - m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs"); -} - -//-------------------------------------------------------------------------------------------------- -// Creating all textures and samplers -// -void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures) -{ - VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.maxLod = FLT_MAX; - - VkFormat format = VK_FORMAT_R8G8B8A8_SRGB; - - // If no textures are present, create a dummy one to accommodate the pipeline layout - if(textures.empty() && m_textures.empty()) - { - nvvk::Texture texture; - - std::array color{255u, 255u, 255u, 255u}; - VkDeviceSize bufferSize = sizeof(color); - auto imgSize = VkExtent2D{1, 1}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format); - - // Creating the dummy texture - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - // The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_textures.push_back(texture); - } - else - { - // Uploading all images - for(const auto& texture : textures) - { - std::stringstream o; - int texWidth, texHeight, texChannels; - o << "media/textures/" << texture; - std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true); - - stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); - - std::array color{255u, 0u, 255u, 255u}; - - stbi_uc* pixels = stbi_pixels; - // Handle failure - if(!stbi_pixels) - { - texWidth = texHeight = 1; - texChannels = 4; - pixels = reinterpret_cast(color.data()); - } - - VkDeviceSize bufferSize = static_cast(texWidth) * texHeight * sizeof(uint8_t) * 4; - auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight}; - auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true); - - { - nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo); - nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo); - nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo); - - m_textures.push_back(texture); - } - - stbi_image_free(stbi_pixels); - } - } -} - -//-------------------------------------------------------------------------------------------------- -// Destroying all allocations -// -void HelloVulkan::destroyResources() -{ - vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_descPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr); - - m_alloc.destroy(m_bGlobals); - m_alloc.destroy(m_bObjDesc); - - for(auto& m : m_objModel) - { - m_alloc.destroy(m.vertexBuffer); - m_alloc.destroy(m.indexBuffer); - m_alloc.destroy(m.matColorBuffer); - m_alloc.destroy(m.matIndexBuffer); - } - - for(auto& t : m_textures) - { - m_alloc.destroy(t); - } - - //#Post - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - vkDestroyPipeline(m_device, m_postPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr); - vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr); - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - - - // #VKRay - m_sbtWrapper.destroy(); - m_rtBuilder.destroy(); - vkDestroyPipeline(m_device, m_rtPipeline, nullptr); - vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); - vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); - vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - - m_alloc.deinit(); -} - -//-------------------------------------------------------------------------------------------------- -// Drawing the scene in raster mode -// -void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) -{ - VkDeviceSize offset{0}; - - m_debug.beginLabel(cmdBuf, "Rasterize"); - - // Dynamic Viewport - setViewport(cmdBuf); - - // Drawing all triangles - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - - - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - auto& model = m_objModel[inst.objIndex]; - m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn - m_pcRaster.modelMatrix = inst.transform; - - vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(PushConstantRaster), &m_pcRaster); - vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset); - vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0); - } - m_debug.endLabel(cmdBuf); -} - -//-------------------------------------------------------------------------------------------------- -// Handling resize of the window -// -void HelloVulkan::onResize(int /*w*/, int /*h*/) -{ - createOffscreenRender(); - updatePostDescriptorSet(); - updateRtDescriptorSet(); -} - - -////////////////////////////////////////////////////////////////////////// -// Post-processing -////////////////////////////////////////////////////////////////////////// - - -//-------------------------------------------------------------------------------------------------- -// Creating an offscreen frame buffer and the associated render pass -// -void HelloVulkan::createOffscreenRender() -{ - m_alloc.destroy(m_offscreenColor); - m_alloc.destroy(m_offscreenDepth); - - // Creating the color image - { - auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT - | VK_IMAGE_USAGE_STORAGE_BIT); - - - nvvk::Image image = m_alloc.createImage(colorCreateInfo); - VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo); - VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler); - m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - } - - // Creating the depth buffer - auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - { - nvvk::Image image = m_alloc.createImage(depthCreateInfo); - - - VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; - depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; - depthStencilView.format = m_offscreenDepthFormat; - depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}; - depthStencilView.image = image.image; - - m_offscreenDepth = m_alloc.createTexture(image, depthStencilView); - } - - // Setting the image layout for both color and depth - { - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - auto cmdBuf = genCmdBuf.createCommandBuffer(); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); - nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT); - - genCmdBuf.submitAndWait(cmdBuf); - } - - // Creating a renderpass for the offscreen - if(!m_offscreenRenderPass) - { - m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true, - true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL); - } - - - // Creating the frame buffer for offscreen - std::vector attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView}; - - vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr); - VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - info.renderPass = m_offscreenRenderPass; - info.attachmentCount = 2; - info.pAttachments = attachments.data(); - info.width = m_size.width; - info.height = m_size.height; - info.layers = 1; - vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer); -} - -//-------------------------------------------------------------------------------------------------- -// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more -// -void HelloVulkan::createPostPipeline() -{ - // Push constants in the fragment shader - VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)}; - - // Creating the pipeline layout - VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - createInfo.setLayoutCount = 1; - createInfo.pSetLayouts = &m_postDescSetLayout; - createInfo.pushConstantRangeCount = 1; - createInfo.pPushConstantRanges = &pushConstantRanges; - vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout); - - - // Pipeline: completely generic, no vertices - nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass); - pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT); - pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT); - pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE; - m_postPipeline = pipelineGenerator.createPipeline(); - m_debug.setObjectName(m_postPipeline, "post"); -} - -//-------------------------------------------------------------------------------------------------- -// The descriptor layout is the description of the data that is passed to the vertex or the -// fragment program. -// -void HelloVulkan::createPostDescriptor() -{ - m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device); - m_postDescPool = m_postDescSetLayoutBind.createPool(m_device); - m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout); -} - - -//-------------------------------------------------------------------------------------------------- -// Update the output -// -void HelloVulkan::updatePostDescriptorSet() -{ - VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor); - vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Draw a full screen quad with the attached image -// -void HelloVulkan::drawPost(VkCommandBuffer cmdBuf) -{ - m_debug.beginLabel(cmdBuf, "Post"); - - setViewport(cmdBuf); - - auto aspectRatio = static_cast(m_size.width) / static_cast(m_size.height); - vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio); - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr); - vkCmdDraw(cmdBuf, 3, 1, 0, 0); - - m_debug.endLabel(cmdBuf); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//-------------------------------------------------------------------------------------------------- -// Initialize Vulkan ray tracing -// #VKRay -void HelloVulkan::initRayTracing() -{ - // Requesting ray tracing properties - VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; - prop2.pNext = &m_rtProperties; - vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2); - - m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); - m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); -} - -//-------------------------------------------------------------------------------------------------- -// Convert an OBJ model into the ray tracing geometry used to build the BLAS -// -auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model) -{ - // BLAS builder requires raw device addresses. - VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer); - VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer); - - uint32_t maxPrimitiveCount = model.nbIndices / 3; - - // Describe buffer as array of VertexObj. - VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR}; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data. - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(VertexObj); - // Describe index data (32-bit unsigned int) - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - // Indicate identity transform by setting transformData to null device pointer. - //triangles.transformData = {}; - triangles.maxVertex = model.nbVertices - 1; - - // Identify the above data as containing opaque triangles. - VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR}; - asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - asGeom.geometry.triangles = triangles; - - // The entire array will be used to build the BLAS. - VkAccelerationStructureBuildRangeInfoKHR offset; - offset.firstVertex = 0; - offset.primitiveCount = maxPrimitiveCount; - offset.primitiveOffset = 0; - offset.transformOffset = 0; - - // Our blas is made from only one geometry, but could be made of many geometries - nvvk::RaytracingBuilderKHR::BlasInput input; - input.asGeometry.emplace_back(asGeom); - input.asBuildOffsetInfo.emplace_back(offset); - - return input; -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createBottomLevelAS() -{ - // BLAS - Storing each primitive in a geometry - std::vector allBlas; - allBlas.reserve(m_objModel.size()); - for(const auto& obj : m_objModel) - { - auto blas = objectToVkGeometryKHR(obj); - - // We could add more geometry in each BLAS, but we add only one for now - allBlas.emplace_back(blas); - } - m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// -// -void HelloVulkan::createTopLevelAS() -{ - std::vector tlas; - tlas.reserve(m_instances.size()); - for(const HelloVulkan::ObjInstance& inst : m_instances) - { - VkAccelerationStructureInstanceKHR rayInst{}; - rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance - rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT - rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex); - rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0 - rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects - tlas.emplace_back(rayInst); - } - m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR); -} - -//-------------------------------------------------------------------------------------------------- -// This descriptor set holds the Acceleration structure and the output image -// -void HelloVulkan::createRtDescriptorSet() -{ - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) - m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS - m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, - VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image - - m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device); - m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device); - - VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; - allocateInfo.descriptorPool = m_rtDescPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &m_rtDescSetLayout; - vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet); - - - VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure(); - VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR}; - descASInfo.accelerationStructureCount = 1; - descASInfo.pAccelerationStructures = &tlas; - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - - std::vector writes; - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo)); - writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo)); - vkUpdateDescriptorSets(m_device, static_cast(writes.size()), writes.data(), 0, nullptr); -} - - -//-------------------------------------------------------------------------------------------------- -// Writes the output image to the descriptor set -// - Required when changing resolution -// -void HelloVulkan::updateRtDescriptorSet() -{ - // (1) Output buffer - VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL}; - VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo); - vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr); -} - - -////////////////////////////////////////////////////////////////////////// -// Helper to generate specialization info -// -class Specialization -{ -public: - void add(uint32_t constantID, int32_t value) - { - spec_values.push_back(value); - VkSpecializationMapEntry entry; - entry.constantID = constantID; - entry.size = sizeof(int32_t); - entry.offset = static_cast(spec_entries.size() * sizeof(int32_t)); - spec_entries.emplace_back(entry); - } - - void add(const std::vector>& const_values) - { - for(const auto& v : const_values) - add(v.first, v.second); - } - - VkSpecializationInfo* getSpecialization() - { - spec_info.dataSize = static_cast(spec_values.size() * sizeof(int32_t)); - spec_info.pData = spec_values.data(); - spec_info.mapEntryCount = static_cast(spec_entries.size()); - spec_info.pMapEntries = spec_entries.data(); - return &spec_info; - } - -private: - std::vector spec_values; - std::vector spec_entries; - VkSpecializationInfo spec_info{}; -}; - - -//-------------------------------------------------------------------------------------------------- -// Pipeline for the ray tracer: all shaders, raygen, chit, miss -// -void HelloVulkan::createRtPipeline() -{ - enum StageIndices - { - eRaygen, - eMiss, - eMiss2, - eClosestHit, // <---- 8 specialization of this one - eShaderGroupCount = 11 - }; - - // Specialization - set 8 permutations of the 3 constant - std::vector specializations(8); - for(int i = 0; i < 8; i++) - { - int a = ((i >> 2) % 2) == 1; - int b = ((i >> 1) % 2) == 1; - int c = ((i >> 0) % 2) == 1; - specializations[i].add({{0, a}, {1, b}, {2, c}}); - } - - - // All stages - std::array stages{}; - VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; - stage.pName = "main"; // All the same entry point - // Raygen - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; - stages[eRaygen] = stage; - // Miss - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss] = stage; - // The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found - stage.module = - nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR; - stages[eMiss2] = stage; - - // Hit Group - Closest Hit - // Create many variation of the closest hit - for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) - { - stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true)); - stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - stage.pSpecializationInfo = specializations[s].getSpecialization(); - stages[eClosestHit + s] = stage; - } - - // Shader groups - VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR}; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - - // Raygen - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eRaygen; - m_rtShaderGroups.push_back(group); - - // Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss; - m_rtShaderGroups.push_back(group); - - // Shadow Miss - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = eMiss2; - m_rtShaderGroups.push_back(group); - - // Hit Group - Closest Hit + AnyHit - // Creating many Hit groups, one for each specialization - for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++) - { - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = eClosestHit + s; // Using variation of the closest hit - m_rtShaderGroups.push_back(group); - } - - // Push constant: we want to be able to update constants used by the shaders - VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay)}; - - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; - pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant; - - // Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline - std::vector rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout}; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(rtDescSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data(); - - vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout); - - - // Assemble the shader stages and recursion depth info into the ray tracing pipeline - VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR}; - rayPipelineInfo.stageCount = static_cast(stages.size()); // Stages are shaders - rayPipelineInfo.pStages = stages.data(); - - // In this case, m_rtShaderGroups.size() == 4: we have one raygen group, - // two miss shader groups, and one hit group. - rayPipelineInfo.groupCount = static_cast(m_rtShaderGroups.size()); - rayPipelineInfo.pGroups = m_rtShaderGroups.data(); - - // The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the - // 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 - // in the ray generation to avoid deep recursion. - rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth - rayPipelineInfo.layout = m_rtPipelineLayout; - - vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); - - m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo); - - // Spec only guarantees 1 level of "recursion". Check for that sad possibility here. - if(m_rtProperties.maxRayRecursionDepth <= 1) - { - throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)"); - } - - for(auto& s : stages) - vkDestroyShaderModule(m_device, s.module, nullptr); -} - -//-------------------------------------------------------------------------------------------------- -// Ray Tracing the scene -// -void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor) -{ - m_debug.beginLabel(cmdBuf, "Ray trace"); - // Initializing push constant values - m_pcRay.clearColor = clearColor; - m_pcRay.lightPosition = m_pcRaster.lightPosition; - m_pcRay.lightIntensity = m_pcRaster.lightIntensity; - m_pcRay.lightType = m_pcRaster.lightType; - - std::vector descSets{m_rtDescSet, m_descSet}; - vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); - vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, - (uint32_t)descSets.size(), descSets.data(), 0, nullptr); - vkCmdPushConstants(cmdBuf, m_rtPipelineLayout, - VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, - 0, sizeof(PushConstantRay), &m_pcRay); - - auto& regions = m_sbtWrapper.getRegions(); - vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); - - m_debug.endLabel(cmdBuf); -} diff --git a/ray_tracing_specialization/hello_vulkan.h b/ray_tracing_specialization/hello_vulkan.h deleted file mode 100644 index 8a005b0..0000000 --- a/ray_tracing_specialization/hello_vulkan.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "nvvkhl/appbase_vk.hpp" -#include "nvvk/debug_util_vk.hpp" -#include "nvvk/descriptorsets_vk.hpp" -#include "nvvk/memallocator_dma_vk.hpp" -#include "nvvk/resourceallocator_vk.hpp" -#include "shaders/host_device.h" - -// #VKRay -#include "nvvk/raytraceKHR_vk.hpp" -#include "nvvk/sbtwrapper_vk.hpp" - -//-------------------------------------------------------------------------------------------------- -// Simple rasterizer of OBJ objects -// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance` -// - It is possible to have many `ObjInstance` referencing the same `ObjModel` -// - Rendering is done in an offscreen framebuffer -// - The image of the framebuffer is displayed in post-process in a full-screen quad -// -class HelloVulkan : public nvvkhl::AppBaseVk -{ -public: - void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override; - void createDescriptorSetLayout(); - void createGraphicsPipeline(); - void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1)); - void updateDescriptorSet(); - void createUniformBuffer(); - void createObjDescriptionBuffer(); - void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector& textures); - void updateUniformBuffer(const VkCommandBuffer& cmdBuf); - void onResize(int /*w*/, int /*h*/) override; - void destroyResources(); - void rasterize(const VkCommandBuffer& cmdBuff); - - // The OBJ model - struct ObjModel - { - uint32_t nbIndices{0}; - uint32_t nbVertices{0}; - nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex' - nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles - nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material' - nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material' - }; - - struct ObjInstance - { - glm::mat4 transform; // Matrix of the instance - uint32_t objIndex{0}; // Model index reference - }; - - - // Information pushed at each draw call - PushConstantRaster m_pcRaster{ - {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix - {10.f, 15.f, 8.f}, // light position - 0, // instance Id - 100.f, // light intensity - 0 // light type - }; - - // Array of objects and instances in the scene - std::vector m_objModel; // Model on host - std::vector m_objDesc; // Model description for device access - std::vector m_instances; // Scene model instances - - - // Graphic pipeline - VkPipelineLayout m_pipelineLayout; - VkPipeline m_graphicsPipeline; - nvvk::DescriptorSetBindings m_descSetLayoutBind; - VkDescriptorPool m_descPool; - VkDescriptorSetLayout m_descSetLayout; - VkDescriptorSet m_descSet; - - nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices - nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions - - std::vector m_textures; // vector of all textures of the scene - - - nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures - nvvk::DebugUtil m_debug; // Utility to name objects - - - // #Post - Draw the rendered image on a quad using a tonemapper - void createOffscreenRender(); - void createPostPipeline(); - void createPostDescriptor(); - void updatePostDescriptorSet(); - void drawPost(VkCommandBuffer cmdBuf); - - nvvk::DescriptorSetBindings m_postDescSetLayoutBind; - VkDescriptorPool m_postDescPool{VK_NULL_HANDLE}; - VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE}; - VkDescriptorSet m_postDescSet{VK_NULL_HANDLE}; - VkPipeline m_postPipeline{VK_NULL_HANDLE}; - VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE}; - VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE}; - VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE}; - nvvk::Texture m_offscreenColor; - nvvk::Texture m_offscreenDepth; - VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT}; - VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32}; - - // #VKRay - void initRayTracing(); - auto objectToVkGeometryKHR(const ObjModel& model); - void createBottomLevelAS(); - void createTopLevelAS(); - void createRtDescriptorSet(); - void updateRtDescriptorSet(); - void createRtPipeline(); - void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor); - - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR}; - nvvk::RaytracingBuilderKHR m_rtBuilder; - nvvk::DescriptorSetBindings m_rtDescSetLayoutBind; - VkDescriptorPool m_rtDescPool; - VkDescriptorSetLayout m_rtDescSetLayout; - VkDescriptorSet m_rtDescSet; - std::vector m_rtShaderGroups; - VkPipelineLayout m_rtPipelineLayout; - VkPipeline m_rtPipeline; - nvvk::SBTWrapper m_sbtWrapper; - - // Push constant for ray tracer - PushConstantRay m_pcRay{{}, {}, 0, 0, 7}; -}; diff --git a/ray_tracing_specialization/images/specialization.png b/ray_tracing_specialization/images/specialization.png deleted file mode 100644 index 8110cbc..0000000 Binary files a/ray_tracing_specialization/images/specialization.png and /dev/null differ diff --git a/ray_tracing_specialization/main.cpp b/ray_tracing_specialization/main.cpp deleted file mode 100644 index a5b5f9c..0000000 --- a/ray_tracing_specialization/main.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -// ImGui - standalone example application for Glfw + Vulkan, using programmable -// pipeline If you are new to ImGui, see examples/README.txt and documentation -// at the top of imgui.cpp. - -#include - -#define IMGUI_DEFINE_MATH_OPERATORS -#include "backends/imgui_impl_glfw.h" -#include "backends/imgui_impl_vulkan.h" -#include "imgui.h" -#include "imgui/imgui_helper.h" - -#include "hello_vulkan.h" -#include "imgui/imgui_camera_widget.h" -#include "nvh/cameramanipulator.hpp" -#include "nvh/fileoperations.hpp" -#include "nvpsystem.hpp" -#include "nvvk/commands_vk.hpp" -#include "nvvk/context_vk.hpp" - - -////////////////////////////////////////////////////////////////////////// -#define UNUSED(x) (void)(x) -////////////////////////////////////////////////////////////////////////// - -// Default search path for shaders -std::vector defaultSearchPaths; - - -// GLFW Callback functions -static void onErrorCallback(int error, const char* description) -{ - fprintf(stderr, "GLFW Error %d: %s\n", error, description); -} - -// Extra UI -void renderUI(HelloVulkan& helloVk) -{ - ImGuiH::CameraWidget(); - if(ImGui::CollapsingHeader("Light")) - { - ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0); - ImGui::SameLine(); - ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1); - - ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f); - ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f); - } - - // Specialization - ImGui::SliderInt("Specialization", &helloVk.m_pcRay.specialization, 0, 7); - int s = helloVk.m_pcRay.specialization; - int a = ((s >> 2) % 2) == 1; - int b = ((s >> 1) % 2) == 1; - int c = ((s >> 0) % 2) == 1; - ImGui::Checkbox("Use Diffuse", (bool*)&a); - ImGui::Checkbox("Use Specular", (bool*)&b); - ImGui::Checkbox("Trace shadow", (bool*)&c); - helloVk.m_pcRay.specialization = (a << 2) + (b << 1) + c; -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -static int const SAMPLE_WIDTH = 1280; -static int const SAMPLE_HEIGHT = 720; - - -//-------------------------------------------------------------------------------------------------- -// Application Entry -// -int main(int argc, char** argv) -{ - UNUSED(argc); - - // Setup GLFW window - glfwSetErrorCallback(onErrorCallback); - if(!glfwInit()) - { - return 1; - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); - - - // Setup camera - CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); - CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)); - - // Setup Vulkan - if(!glfwVulkanSupported()) - { - printf("GLFW: Vulkan Not Supported\n"); - return 1; - } - - // setup some basic things for the sample, logging file for example - NVPSystem system(PROJECT_NAME); - - // Search path for shaders and other media - defaultSearchPaths = { - NVPSystem::exePath() + PROJECT_RELDIRECTORY, - NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", - std::string(PROJECT_NAME), - }; - - // Vulkan required extensions - assert(glfwVulkanSupported() == 1); - uint32_t count{0}; - auto reqExtensions = glfwGetRequiredInstanceExtensions(&count); - - // Requesting Vulkan extensions and layers - nvvk::ContextCreateInfo contextInfo; - contextInfo.setVersion(1, 2); // Using Vulkan 1.2 - for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..) - contextInfo.addInstanceExtension(reqExtensions[ext_id]); - contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar - contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names - contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering - - // #VKRay: Activate the ray tracing extension - VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures - VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR}; - contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR - contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline - - // Creating Vulkan base application - nvvk::Context vkctx{}; - vkctx.initInstance(contextInfo); - // Find all compatible devices - auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); - assert(!compatibleDevices.empty()); - // Use a compatible device - vkctx.initDevice(compatibleDevices[0], contextInfo); - - // Create example - HelloVulkan helloVk; - - // Window need to be opened to get the surface on which to draw - const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); - vkctx.setGCTQueueWithPresent(surface); - - helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); - helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); - helloVk.createDepthBuffer(); - helloVk.createRenderPass(); - helloVk.createFrameBuffers(); - - // Setup Imgui - helloVk.initGUI(0); // Using sub-pass 0 - - // Creation of the example - helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); - helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); - - helloVk.createOffscreenRender(); - helloVk.createDescriptorSetLayout(); - helloVk.createGraphicsPipeline(); - helloVk.createUniformBuffer(); - helloVk.createObjDescriptionBuffer(); - helloVk.updateDescriptorSet(); - - // #VKRay - helloVk.initRayTracing(); - helloVk.createBottomLevelAS(); - helloVk.createTopLevelAS(); - helloVk.createRtDescriptorSet(); - helloVk.createRtPipeline(); - - helloVk.createPostDescriptor(); - helloVk.createPostPipeline(); - helloVk.updatePostDescriptorSet(); - - - glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f); - bool useRaytracer = true; - - - helloVk.setupGlfwCallbacks(window); - ImGui_ImplGlfw_InitForVulkan(window, true); - - // Main loop - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - if(helloVk.isMinimized()) - continue; - - // Start the Dear ImGui frame - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - - // Show UI window. - if(helloVk.showGui()) - { - ImGuiH::Panel::Begin(); - ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); - ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing - - renderUI(helloVk); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); - ImGuiH::Panel::End(); - } - - // Start rendering the scene - helloVk.prepareFrame(); - - // Start command buffer of this frame - auto curFrame = helloVk.getCurFrame(); - const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; - - VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkBeginCommandBuffer(cmdBuf, &beginInfo); - - // Updating camera buffer - helloVk.updateUniformBuffer(cmdBuf); - - // Clearing screen - std::array clearValues{}; - clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}}; - clearValues[1].depthStencil = {1.0f, 0}; - - // Offscreen render pass - { - VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - offscreenRenderPassBeginInfo.clearValueCount = 2; - offscreenRenderPassBeginInfo.pClearValues = clearValues.data(); - offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass; - offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer; - offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering Scene - if(useRaytracer) - { - helloVk.raytrace(cmdBuf, clearColor); - } - else - { - vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.rasterize(cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - } - - // 2nd rendering pass: tone mapper, UI - { - VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO}; - postRenderPassBeginInfo.clearValueCount = 2; - postRenderPassBeginInfo.pClearValues = clearValues.data(); - postRenderPassBeginInfo.renderPass = helloVk.getRenderPass(); - postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame]; - postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()}; - - // Rendering tonemapper - vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - helloVk.drawPost(cmdBuf); - // Rendering UI - ImGui::Render(); - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); - vkCmdEndRenderPass(cmdBuf); - } - - // Submit for display - vkEndCommandBuffer(cmdBuf); - helloVk.submitFrame(); - } - - // Cleanup - vkDeviceWaitIdle(helloVk.getDevice()); - - helloVk.destroyResources(); - helloVk.destroy(); - vkctx.deinit(); - - glfwDestroyWindow(window); - glfwTerminate(); - - return 0; -} diff --git a/ray_tracing_specialization/shaders/frag_shader.frag b/ray_tracing_specialization/shaders/frag_shader.frag deleted file mode 100644 index 0930980..0000000 --- a/ray_tracing_specialization/shaders/frag_shader.frag +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_scalar_block_layout : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "wavefront.glsl" - - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -// clang-format off -// Incoming -layout(location = 1) in vec3 i_worldPos; -layout(location = 2) in vec3 i_worldNrm; -layout(location = 3) in vec3 i_viewDir; -layout(location = 4) in vec2 i_texCoord; -// Outgoing -layout(location = 0) out vec4 o_color; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle - -layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(binding = eTextures) uniform sampler2D[] textureSamplers; -// clang-format on - - -void main() -{ - // Material of the object - ObjDesc objResource = objDesc.i[pcRaster.objIndex]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - - int matIndex = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIndex]; - - vec3 N = normalize(i_worldNrm); - - // Vector toward light - vec3 L; - float lightIntensity = pcRaster.lightIntensity; - if(pcRaster.lightType == 0) - { - vec3 lDir = pcRaster.lightPosition - i_worldPos; - float d = length(lDir); - lightIntensity = pcRaster.lightIntensity / (d * d); - L = normalize(lDir); - } - else - { - L = normalize(pcRaster.lightPosition); - } - - - // Diffuse - vec3 diffuse = computeDiffuse(mat, L, N); - if(mat.textureId >= 0) - { - int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset; - uint txtId = txtOffset + mat.textureId; - vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz; - diffuse *= diffuseTxt; - } - - // Specular - vec3 specular = computeSpecular(mat, i_viewDir, L, N); - - // Result - o_color = vec4(lightIntensity * (diffuse + specular), 1); -} diff --git a/ray_tracing_specialization/shaders/host_device.h b/ray_tracing_specialization/shaders/host_device.h deleted file mode 100644 index 11265e8..0000000 --- a/ray_tracing_specialization/shaders/host_device.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - - -#ifndef COMMON_HOST_DEVICE -#define COMMON_HOST_DEVICE - -#ifdef __cplusplus -#include -// GLSL Type -using vec2 = glm::vec2; -using vec3 = glm::vec3; -using vec4 = glm::vec4; -using mat4 = glm::mat4; -using uint = unsigned int; -#endif - -// clang-format off -#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL - #define START_BINDING(a) enum a { - #define END_BINDING() } -#else - #define START_BINDING(a) const uint - #define END_BINDING() -#endif - -START_BINDING(SceneBindings) - eGlobals = 0, // Global uniform containing camera matrices - eObjDescs = 1, // Access to the object descriptions - eTextures = 2 // Access to textures -END_BINDING(); - -START_BINDING(RtxBindings) - eTlas = 0, // Top-level acceleration structure - eOutImage = 1 // Ray tracer output image -END_BINDING(); -// clang-format on - - -// Information of a obj model when referenced in a shader -struct ObjDesc -{ - int txtOffset; // Texture index offset in the array of textures - uint64_t vertexAddress; // Address of the Vertex buffer - uint64_t indexAddress; // Address of the index buffer - uint64_t materialAddress; // Address of the material buffer - uint64_t materialIndexAddress; // Address of the triangle material index buffer -}; - -// Uniform buffer set at each frame -struct GlobalUniforms -{ - mat4 viewProj; // Camera view * projection - mat4 viewInverse; // Camera inverse view matrix - mat4 projInverse; // Camera inverse projection matrix -}; - -// Push constant structure for the raster -struct PushConstantRaster -{ - mat4 modelMatrix; // matrix of the instance - vec3 lightPosition; - uint objIndex; - float lightIntensity; - int lightType; -}; - - -// Push constant structure for the ray tracer -struct PushConstantRay -{ - vec4 clearColor; - vec3 lightPosition; - float lightIntensity; - int lightType; - int specialization; -}; - -struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device -{ - vec3 pos; - vec3 nrm; - vec3 color; - vec2 texCoord; -}; - -struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device -{ - vec3 ambient; - vec3 diffuse; - vec3 specular; - vec3 transmittance; - vec3 emission; - float shininess; - float ior; // index of refraction - float dissolve; // 1 == opaque; 0 == fully transparent - int illum; // illumination model (see http://www.fileformat.info/format/material/) - int textureId; -}; - - -#endif diff --git a/ray_tracing_specialization/shaders/passthrough.vert b/ray_tracing_specialization/shaders/passthrough.vert deleted file mode 100644 index 65c3460..0000000 --- a/ray_tracing_specialization/shaders/passthrough.vert +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) out vec2 outUV; - - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f); -} diff --git a/ray_tracing_specialization/shaders/post.frag b/ray_tracing_specialization/shaders/post.frag deleted file mode 100644 index 85faa58..0000000 --- a/ray_tracing_specialization/shaders/post.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -layout(location = 0) in vec2 outUV; -layout(location = 0) out vec4 fragColor; - -layout(set = 0, binding = 0) uniform sampler2D noisyTxt; - -layout(push_constant) uniform shaderInformation -{ - float aspectRatio; -} -pushc; - -void main() -{ - vec2 uv = outUV; - float gamma = 1. / 2.2; - fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma)); -} diff --git a/ray_tracing_specialization/shaders/raycommon.glsl b/ray_tracing_specialization/shaders/raycommon.glsl deleted file mode 100644 index b896c84..0000000 --- a/ray_tracing_specialization/shaders/raycommon.glsl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -struct hitPayload -{ - vec3 hitValue; -}; diff --git a/ray_tracing_specialization/shaders/raytrace.rchit b/ray_tracing_specialization/shaders/raytrace.rchit deleted file mode 100644 index 0f6b022..0000000 --- a/ray_tracing_specialization/shaders/raytrace.rchit +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#extension GL_EXT_buffer_reference2 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -hitAttributeEXT vec2 attribs; - -// clang-format off -layout(location = 0) rayPayloadInEXT hitPayload prd; -layout(location = 1) rayPayloadEXT bool isShadowed; - -layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object -layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices -layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object -layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc; -layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[]; - -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; - -layout(constant_id = 0) const int USE_DIFFUSE = 1; -layout(constant_id = 1) const int USE_SPECULAR = 1; -layout(constant_id = 2) const int TRACE_SHADOW = 1; - -// clang-format on - - -void main() -{ - // Object data - ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT]; - MatIndices matIndices = MatIndices(objResource.materialIndexAddress); - Materials materials = Materials(objResource.materialAddress); - Indices indices = Indices(objResource.indexAddress); - Vertices vertices = Vertices(objResource.vertexAddress); - - // Indices of the triangle - ivec3 ind = indices.i[gl_PrimitiveID]; - - // Vertex of the triangle - Vertex v0 = vertices.v[ind.x]; - Vertex v1 = vertices.v[ind.y]; - Vertex v2 = vertices.v[ind.z]; - - const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); - - // Computing the coordinates of the hit position - const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z; - const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space - - // Computing the normal at hit position - const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z; - const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space - - // Vector toward the light - vec3 L; - float lightIntensity = pcRay.lightIntensity; - float lightDistance = 100000.0; - // Point light - if(pcRay.lightType == 0) - { - vec3 lDir = pcRay.lightPosition - worldPos; - lightDistance = length(lDir); - lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance); - L = normalize(lDir); - } - else // Directional light - { - L = normalize(pcRay.lightPosition); - } - - // Material of the object - int matIdx = matIndices.i[gl_PrimitiveID]; - WaveFrontMaterial mat = materials.m[matIdx]; - - - // Diffuse - vec3 diffuse = vec3(0); - if(USE_DIFFUSE == 1) - { - diffuse = computeDiffuse(mat, L, worldNrm); - if(mat.textureId >= 0) - { - uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset; - vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z; - diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz; - } - } - - vec3 specular = vec3(0); - float attenuation = 1; - - // Tracing shadow ray only if the light is visible from the surface - if(dot(worldNrm, L) > 0) - { - if(TRACE_SHADOW == 1) - { - float tMin = 0.001; - float tMax = lightDistance; - vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - vec3 rayDir = L; - uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT; - isShadowed = true; - traceRayEXT(topLevelAS, // acceleration structure - flags, // rayFlags - 0xFF, // cullMask - 0, // sbtRecordOffset - 0, // sbtRecordStride - 1, // missIndex - origin, // ray origin - tMin, // ray min range - rayDir, // ray direction - tMax, // ray max range - 1 // payload (location = 1) - ); - } - else - isShadowed = false; - - if(isShadowed) - { - attenuation = 0.3; - } - else - { - // Specular - if(USE_SPECULAR == 1) - { - specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm); - } - } - } - - prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular)); -} diff --git a/ray_tracing_specialization/shaders/raytrace.rgen b/ray_tracing_specialization/shaders/raytrace.rgen deleted file mode 100644 index c2ba199..0000000 --- a/ray_tracing_specialization/shaders/raytrace.rgen +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - - -#include "raycommon.glsl" -#include "wavefront.glsl" - -// clang-format off -layout(location = 0) rayPayloadEXT hitPayload prd; - -layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS; -layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image; -layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; }; -layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; }; -// clang-format on - - -void main() -{ - const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5); - const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy); - vec2 d = inUV * 2.0 - 1.0; - - vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1); - vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1); - vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0); - - uint rayFlags = gl_RayFlagsOpaqueEXT; - float tMin = 0.001; - float tMax = 10000.0; - - traceRayEXT(topLevelAS, // acceleration structure - rayFlags, // rayFlags - 0xFF, // cullMask - pcRay.specialization, // sbtRecordOffset - 0, // sbtRecordStride - 0, // missIndex - origin.xyz, // ray origin - tMin, // ray min range - direction.xyz, // ray direction - tMax, // ray max range - 0 // payload (location = 0) - ); - - imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0)); -} diff --git a/ray_tracing_specialization/shaders/raytrace.rmiss b/ray_tracing_specialization/shaders/raytrace.rmiss deleted file mode 100644 index 368a93f..0000000 --- a/ray_tracing_specialization/shaders/raytrace.rmiss +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require -#extension GL_GOOGLE_include_directive : enable -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "raycommon.glsl" -#include "wavefront.glsl" - -layout(location = 0) rayPayloadInEXT hitPayload prd; - -layout(push_constant) uniform _PushConstantRay -{ - PushConstantRay pcRay; -}; - -void main() -{ - prd.hitValue = pcRay.clearColor.xyz * 0.8; -} diff --git a/ray_tracing_specialization/shaders/raytraceShadow.rmiss b/ray_tracing_specialization/shaders/raytraceShadow.rmiss deleted file mode 100644 index bf99caf..0000000 --- a/ray_tracing_specialization/shaders/raytraceShadow.rmiss +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 1) rayPayloadInEXT bool isShadowed; - -void main() -{ - isShadowed = false; -} diff --git a/ray_tracing_specialization/shaders/vert_shader.vert b/ray_tracing_specialization/shaders/vert_shader.vert deleted file mode 100644 index 40baa80..0000000 --- a/ray_tracing_specialization/shaders/vert_shader.vert +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_EXT_scalar_block_layout : enable -#extension GL_GOOGLE_include_directive : enable - -#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require - -#include "wavefront.glsl" - -layout(binding = 0) uniform _GlobalUniforms -{ - GlobalUniforms uni; -}; - -layout(push_constant) uniform _PushConstantRaster -{ - PushConstantRaster pcRaster; -}; - -layout(location = 0) in vec3 i_position; -layout(location = 1) in vec3 i_normal; -layout(location = 2) in vec3 i_color; -layout(location = 3) in vec2 i_texCoord; - - -layout(location = 1) out vec3 o_worldPos; -layout(location = 2) out vec3 o_worldNrm; -layout(location = 3) out vec3 o_viewDir; -layout(location = 4) out vec2 o_texCoord; - -out gl_PerVertex -{ - vec4 gl_Position; -}; - - -void main() -{ - vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1)); - - o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0)); - o_viewDir = vec3(o_worldPos - origin); - o_texCoord = i_texCoord; - o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal; - - gl_Position = uni.viewProj * vec4(o_worldPos, 1.0); -} diff --git a/ray_tracing_specialization/shaders/wavefront.glsl b/ray_tracing_specialization/shaders/wavefront.glsl deleted file mode 100644 index b326f8a..0000000 --- a/ray_tracing_specialization/shaders/wavefront.glsl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host_device.h" - -vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal) -{ - // Lambertian - float dotNL = max(dot(normal, lightDir), 0.0); - vec3 c = mat.diffuse * dotNL; - if(mat.illum >= 1) - c += mat.ambient; - return c; -} - -vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal) -{ - if(mat.illum < 2) - return vec3(0); - - // Compute specular only if not in shadow - const float kPi = 3.14159265; - const float kShininess = max(mat.shininess, 4.0); - - // Specular - const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi); - vec3 V = normalize(-viewDir); - vec3 R = reflect(-lightDir, normal); - float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess); - - return vec3(mat.specular * specular); -}